Jalview-JS/JAL-3253 applet params jpredfile, jnetfile
[jalview.git] / src / jalview / bin / JalviewLite.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.analysis.AlignmentUtils;
24 import jalview.api.AlignViewportI;
25 import jalview.api.JalviewApp;
26 import jalview.api.StructureSelectionManagerProvider;
27 import jalview.appletgui.AlignFrame;
28 import jalview.appletgui.AlignViewport;
29 import jalview.appletgui.EmbmenuFrame;
30 import jalview.appletgui.FeatureSettings;
31 import jalview.appletgui.SplitFrame;
32 import jalview.datamodel.Alignment;
33 import jalview.datamodel.AlignmentI;
34 import jalview.datamodel.AlignmentOrder;
35 import jalview.datamodel.ColumnSelection;
36 import jalview.datamodel.PDBEntry;
37 import jalview.datamodel.SequenceGroup;
38 import jalview.datamodel.SequenceI;
39 import jalview.io.AnnotationFile;
40 import jalview.io.AppletFormatAdapter;
41 import jalview.io.DataSourceType;
42 import jalview.io.FileFormatI;
43 import jalview.io.FileFormats;
44 import jalview.io.FileParse;
45 import jalview.io.IdentifyFile;
46 import jalview.io.NewickFile;
47 import jalview.javascript.JSFunctionExec;
48 import jalview.javascript.JalviewLiteJsApi;
49 import jalview.javascript.JsCallBack;
50 import jalview.javascript.MouseOverStructureListener;
51 import jalview.structure.SelectionListener;
52 import jalview.structure.StructureSelectionManager;
53 import jalview.util.ColorUtils;
54 import jalview.util.MessageManager;
55
56 import java.applet.Applet;
57 import java.awt.Button;
58 import java.awt.Color;
59 import java.awt.Component;
60 import java.awt.EventQueue;
61 import java.awt.Font;
62 import java.awt.Frame;
63 import java.awt.Graphics;
64 import java.awt.event.ActionEvent;
65 import java.awt.event.WindowAdapter;
66 import java.awt.event.WindowEvent;
67 import java.io.BufferedReader;
68 import java.io.IOException;
69 import java.io.InputStreamReader;
70 import java.net.URL;
71 import java.util.ArrayList;
72 import java.util.Hashtable;
73 import java.util.List;
74 import java.util.Vector;
75
76 import netscape.javascript.JSObject;
77
78 /**
79  * Jalview Applet. Runs in Java 1.18 runtime
80  * 
81  * @author $author$
82  * @version $Revision: 1.92 $
83  */
84 public class JalviewLite extends Applet
85         implements StructureSelectionManagerProvider, JalviewLiteJsApi,
86         JalviewApp
87 {
88
89   public JalviewLite()
90   {
91     appLoader = new JalviewAppLoader(debug);
92   }
93   private static final String TRUE = "true";
94
95   private static final String FALSE = "false";
96
97   public StructureSelectionManager getStructureSelectionManager()
98   {
99     return StructureSelectionManager.getStructureSelectionManager(this);
100   }
101
102   // /////////////////////////////////////////
103   // The following public methods may be called
104   // externally, eg via javascript in HTML page
105   /*
106    * (non-Javadoc)
107    * 
108    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences()
109    */
110   @Override
111   public String getSelectedSequences()
112   {
113     return getSelectedSequencesFrom(getDefaultTargetFrame());
114   }
115
116   /*
117    * (non-Javadoc)
118    * 
119    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences(java.lang.String)
120    */
121   @Override
122   public String getSelectedSequences(String sep)
123   {
124     return getSelectedSequencesFrom(getDefaultTargetFrame(), sep);
125   }
126
127   /*
128    * (non-Javadoc)
129    * 
130    * @see
131    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
132    * .AlignFrame)
133    */
134   @Override
135   public String getSelectedSequencesFrom(AlignFrame alf)
136   {
137     return getSelectedSequencesFrom(alf, separator); // ""+0x00AC);
138   }
139
140   /*
141    * (non-Javadoc)
142    * 
143    * @see
144    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
145    * .AlignFrame, java.lang.String)
146    */
147   @Override
148   public String getSelectedSequencesFrom(AlignFrame alf, String sep)
149   {
150     StringBuffer result = new StringBuffer("");
151     if (sep == null || sep.length() == 0)
152     {
153       sep = separator; // "+0x00AC;
154     }
155     if (alf.viewport.getSelectionGroup() != null)
156     {
157       SequenceI[] seqs = alf.viewport.getSelectionGroup()
158               .getSequencesInOrder(alf.viewport.getAlignment());
159
160       for (int i = 0; i < seqs.length; i++)
161       {
162         result.append(seqs[i].getName());
163         result.append(sep);
164       }
165     }
166
167     return result.toString();
168   }
169
170   /*
171    * (non-Javadoc)
172    * 
173    * @see jalview.bin.JalviewLiteJsApi#highlight(java.lang.String,
174    * java.lang.String, java.lang.String)
175    */
176   @Override
177   public void highlight(String sequenceId, String position,
178           String alignedPosition)
179   {
180     highlightIn(getDefaultTargetFrame(), sequenceId, position,
181             alignedPosition);
182   }
183
184   /*
185    * (non-Javadoc)
186    * 
187    * @see jalview.bin.JalviewLiteJsApi#highlightIn(jalview.appletgui.AlignFrame,
188    * java.lang.String, java.lang.String, java.lang.String)
189    */
190   @Override
191   public void highlightIn(final AlignFrame alf, final String sequenceId,
192           final String position, final String alignedPosition)
193   {
194     // TODO: could try to highlight in all alignments if alf==null
195     jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
196             alf.viewport.getAlignment().getSequencesArray());
197     final SequenceI sq = matcher.findIdMatch(sequenceId);
198     if (sq != null)
199     {
200       int apos = -1;
201       try
202       {
203         apos = new Integer(position).intValue();
204         apos--;
205       } catch (NumberFormatException ex)
206       {
207         return;
208       }
209       final StructureSelectionManagerProvider me = this;
210       final int pos = apos;
211       // use vamsas listener to broadcast to all listeners in scope
212       if (alignedPosition != null && (alignedPosition.trim().length() == 0
213               || alignedPosition.toLowerCase().indexOf("false") > -1))
214       {
215         java.awt.EventQueue.invokeLater(new Runnable()
216         {
217           @Override
218           public void run()
219           {
220             StructureSelectionManager.getStructureSelectionManager(me)
221                     .mouseOverVamsasSequence(sq, sq.findIndex(pos), null);
222           }
223         });
224       }
225       else
226       {
227         java.awt.EventQueue.invokeLater(new Runnable()
228         {
229           @Override
230           public void run()
231           {
232             StructureSelectionManager.getStructureSelectionManager(me)
233                     .mouseOverVamsasSequence(sq, pos, null);
234           }
235         });
236       }
237     }
238   }
239
240   /*
241    * (non-Javadoc)
242    * 
243    * @see jalview.bin.JalviewLiteJsApi#select(java.lang.String,
244    * java.lang.String)
245    */
246   @Override
247   public void select(String sequenceIds, String columns)
248   {
249     selectIn(getDefaultTargetFrame(), sequenceIds, columns, separator);
250   }
251
252   /*
253    * (non-Javadoc)
254    * 
255    * @see jalview.bin.JalviewLiteJsApi#select(java.lang.String,
256    * java.lang.String, java.lang.String)
257    */
258   @Override
259   public void select(String sequenceIds, String columns, String sep)
260   {
261     selectIn(getDefaultTargetFrame(), sequenceIds, columns, sep);
262   }
263
264   /*
265    * (non-Javadoc)
266    * 
267    * @see jalview.bin.JalviewLiteJsApi#selectIn(jalview.appletgui.AlignFrame,
268    * java.lang.String, java.lang.String)
269    */
270   @Override
271   public void selectIn(AlignFrame alf, String sequenceIds, String columns)
272   {
273     selectIn(alf, sequenceIds, columns, separator);
274   }
275
276   /*
277    * (non-Javadoc)
278    * 
279    * @see jalview.bin.JalviewLiteJsApi#selectIn(jalview.appletgui.AlignFrame,
280    * java.lang.String, java.lang.String, java.lang.String)
281    */
282   @Override
283   public void selectIn(final AlignFrame alf, String sequenceIds,
284           String columns, String sep)
285   {
286     if (sep == null || sep.length() == 0)
287     {
288       sep = separator;
289     }
290     else
291     {
292       if (debug)
293       {
294         System.err.println("Selecting region using separator string '"
295                 + separator + "'");
296       }
297     }
298     // deparse fields
299     String[] ids = JalviewAppLoader.separatorListToArray(sequenceIds, sep);
300     String[] cols = JalviewAppLoader.separatorListToArray(columns, sep);
301     final SequenceGroup sel = new SequenceGroup();
302     final ColumnSelection csel = new ColumnSelection();
303     AlignmentI al = alf.viewport.getAlignment();
304     jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
305             alf.viewport.getAlignment().getSequencesArray());
306     int start = 0, end = al.getWidth(), alw = al.getWidth();
307     boolean seqsfound = true;
308     if (ids != null && ids.length > 0)
309     {
310       seqsfound = false;
311       for (int i = 0; i < ids.length; i++)
312       {
313         if (ids[i].trim().length() == 0)
314         {
315           continue;
316         }
317         SequenceI sq = matcher.findIdMatch(ids[i]);
318         if (sq != null)
319         {
320           seqsfound = true;
321           sel.addSequence(sq, false);
322         }
323       }
324     }
325     boolean inseqpos = false;
326     if (cols != null && cols.length > 0)
327     {
328       boolean seset = false;
329       for (int i = 0; i < cols.length; i++)
330       {
331         String cl = cols[i].trim();
332         if (cl.length() == 0)
333         {
334           continue;
335         }
336         int p;
337         if ((p = cl.indexOf("-")) > -1)
338         {
339           int from = -1, to = -1;
340           try
341           {
342             from = new Integer(cl.substring(0, p)).intValue();
343             from--;
344           } catch (NumberFormatException ex)
345           {
346             System.err.println(
347                     "ERROR: Couldn't parse first integer in range element column selection string '"
348                             + cl + "' - format is 'from-to'");
349             return;
350           }
351           try
352           {
353             to = new Integer(cl.substring(p + 1)).intValue();
354             to--;
355           } catch (NumberFormatException ex)
356           {
357             System.err.println(
358                     "ERROR: Couldn't parse second integer in range element column selection string '"
359                             + cl + "' - format is 'from-to'");
360             return;
361           }
362           if (from >= 0 && to >= 0)
363           {
364             // valid range
365             if (from < to)
366             {
367               int t = to;
368               to = from;
369               to = t;
370             }
371             if (!seset)
372             {
373               start = from;
374               end = to;
375               seset = true;
376             }
377             else
378             {
379               // comment to prevent range extension
380               if (start > from)
381               {
382                 start = from;
383               }
384               if (end < to)
385               {
386                 end = to;
387               }
388             }
389             for (int r = from; r <= to; r++)
390             {
391               if (r >= 0 && r < alw)
392               {
393                 csel.addElement(r);
394               }
395             }
396             if (debug)
397             {
398               System.err.println("Range '" + cl + "' deparsed as [" + from
399                       + "," + to + "]");
400             }
401           }
402           else
403           {
404             System.err.println("ERROR: Invalid Range '" + cl
405                     + "' deparsed as [" + from + "," + to + "]");
406           }
407         }
408         else
409         {
410           int r = -1;
411           try
412           {
413             r = new Integer(cl).intValue();
414             r--;
415           } catch (NumberFormatException ex)
416           {
417             if (cl.toLowerCase().equals("sequence"))
418             {
419               // we are in the dataset sequence's coordinate frame.
420               inseqpos = true;
421             }
422             else
423             {
424               System.err.println(
425                       "ERROR: Couldn't parse integer from point selection element of column selection string '"
426                               + cl + "'");
427               return;
428             }
429           }
430           if (r >= 0 && r <= alw)
431           {
432             if (!seset)
433             {
434               start = r;
435               end = r;
436               seset = true;
437             }
438             else
439             {
440               // comment to prevent range extension
441               if (start > r)
442               {
443                 start = r;
444               }
445               if (end < r)
446               {
447                 end = r;
448               }
449             }
450             csel.addElement(r);
451             if (debug)
452             {
453               System.err.println("Point selection '" + cl
454                       + "' deparsed as [" + r + "]");
455             }
456           }
457           else
458           {
459             System.err.println("ERROR: Invalid Point selection '" + cl
460                     + "' deparsed as [" + r + "]");
461           }
462         }
463       }
464     }
465     if (seqsfound)
466     {
467       // we only propagate the selection when it was the null selection, or the
468       // given sequences were found in the alignment.
469       if (inseqpos && sel.getSize() > 0)
470       {
471         // assume first sequence provides reference frame ?
472         SequenceI rs = sel.getSequenceAt(0);
473         start = rs.findIndex(start);
474         end = rs.findIndex(end);
475         List<Integer> cs = new ArrayList<>(csel.getSelected());
476         csel.clear();
477         for (Integer selectedCol : cs)
478         {
479           csel.addElement(rs.findIndex(selectedCol));
480         }
481       }
482       sel.setStartRes(start);
483       sel.setEndRes(end);
484       EventQueue.invokeLater(new Runnable()
485       {
486         @Override
487         public void run()
488         {
489           alf.select(sel, csel,
490                   alf.getAlignViewport().getAlignment().getHiddenColumns());
491         }
492       });
493     }
494   }
495
496   /*
497    * (non-Javadoc)
498    * 
499    * @see
500    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesAsAlignment(java.lang.
501    * String, java.lang.String)
502    */
503   @Override
504   public String getSelectedSequencesAsAlignment(String format,
505           String suffix)
506   {
507     return getSelectedSequencesAsAlignmentFrom(getDefaultTargetFrame(),
508             format, suffix);
509   }
510
511   /*
512    * (non-Javadoc)
513    * 
514    * @see
515    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesAsAlignmentFrom(jalview
516    * .appletgui.AlignFrame, java.lang.String, java.lang.String)
517    */
518   @Override
519   public String getSelectedSequencesAsAlignmentFrom(AlignFrame alf,
520           String format, String suffix)
521   {
522     try
523     {
524       FileFormatI theFormat = FileFormats.getInstance().forName(format);
525       boolean seqlimits = suffix.equalsIgnoreCase(TRUE);
526       if (alf.viewport.getSelectionGroup() != null)
527       {
528         // JBPNote: getSelectionAsNewSequence behaviour has changed - this
529         // method now returns a full copy of sequence data
530         // TODO consider using getSequenceSelection instead here
531         String reply = new AppletFormatAdapter().formatSequences(theFormat,
532                 new Alignment(alf.viewport.getSelectionAsNewSequence()),
533                 seqlimits);
534         return reply;
535       }
536     } catch (IllegalArgumentException ex)
537     {
538       ex.printStackTrace();
539       return "Error retrieving alignment, possibly invalid format specifier: "
540               + format;
541     }
542     return "";
543   }
544
545   /*
546    * (non-Javadoc)
547    * 
548    * @see jalview.bin.JalviewLiteJsApi#getAlignmentOrder()
549    */
550   @Override
551   public String getAlignmentOrder()
552   {
553     return getAlignmentOrderFrom(getDefaultTargetFrame());
554   }
555
556   /*
557    * (non-Javadoc)
558    * 
559    * @see
560    * jalview.bin.JalviewLiteJsApi#getAlignmentOrderFrom(jalview.appletgui.AlignFrame
561    * )
562    */
563   @Override
564   public String getAlignmentOrderFrom(AlignFrame alf)
565   {
566     return getAlignmentOrderFrom(alf, separator);
567   }
568
569   /*
570    * (non-Javadoc)
571    * 
572    * @see
573    * jalview.bin.JalviewLiteJsApi#getAlignmentOrderFrom(jalview.appletgui.AlignFrame
574    * , java.lang.String)
575    */
576   @Override
577   public String getAlignmentOrderFrom(AlignFrame alf, String sep)
578   {
579     AlignmentI alorder = alf.getAlignViewport().getAlignment();
580     String[] order = new String[alorder.getHeight()];
581     for (int i = 0; i < order.length; i++)
582     {
583       order[i] = alorder.getSequenceAt(i).getName();
584     }
585     return arrayToSeparatorList(order);
586   }
587
588   /*
589    * (non-Javadoc)
590    * 
591    * @see jalview.bin.JalviewLiteJsApi#orderBy(java.lang.String,
592    * java.lang.String)
593    */
594   @Override
595   public String orderBy(String order, String undoName)
596   {
597     return orderBy(order, undoName, separator);
598   }
599
600   /*
601    * (non-Javadoc)
602    * 
603    * @see jalview.bin.JalviewLiteJsApi#orderBy(java.lang.String,
604    * java.lang.String, java.lang.String)
605    */
606   @Override
607   public String orderBy(String order, String undoName, String sep)
608   {
609     return orderAlignmentBy(getDefaultTargetFrame(), order, undoName, sep);
610   }
611
612   /*
613    * (non-Javadoc)
614    * 
615    * @see
616    * jalview.bin.JalviewLiteJsApi#orderAlignmentBy(jalview.appletgui.AlignFrame,
617    * java.lang.String, java.lang.String, java.lang.String)
618    */
619   @Override
620   public String orderAlignmentBy(AlignFrame alf, String order,
621           String undoName, String sep)
622   {
623     String[] ids = JalviewAppLoader.separatorListToArray(order, sep);
624     SequenceI[] sqs = null;
625     if (ids != null && ids.length > 0)
626     {
627       jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
628               alf.viewport.getAlignment().getSequencesArray());
629       int s = 0;
630       sqs = new SequenceI[ids.length];
631       for (int i = 0; i < ids.length; i++)
632       {
633         if (ids[i].trim().length() == 0)
634         {
635           continue;
636         }
637         SequenceI sq = matcher.findIdMatch(ids[i]);
638         if (sq != null)
639         {
640           sqs[s++] = sq;
641         }
642       }
643       if (s > 0)
644       {
645         SequenceI[] sqq = new SequenceI[s];
646         System.arraycopy(sqs, 0, sqq, 0, s);
647         sqs = sqq;
648       }
649       else
650       {
651         sqs = null;
652       }
653     }
654     if (sqs == null)
655     {
656       return "";
657     }
658     ;
659     final AlignmentOrder aorder = new AlignmentOrder(sqs);
660
661     if (undoName != null && undoName.trim().length() == 0)
662     {
663       undoName = null;
664     }
665     final String _undoName = undoName;
666     // TODO: deal with synchronization here: cannot raise any events until after
667     // this has returned.
668     return alf.sortBy(aorder, _undoName) ? TRUE : "";
669   }
670
671   /*
672    * (non-Javadoc)
673    * 
674    * @see jalview.bin.JalviewLiteJsApi#getAlignment(java.lang.String)
675    */
676   @Override
677   public String getAlignment(String format)
678   {
679     return getAlignmentFrom(getDefaultTargetFrame(), format, TRUE);
680   }
681
682   /*
683    * (non-Javadoc)
684    * 
685    * @see
686    * jalview.bin.JalviewLiteJsApi#getAlignmentFrom(jalview.appletgui.AlignFrame,
687    * java.lang.String)
688    */
689   @Override
690   public String getAlignmentFrom(AlignFrame alf, String format)
691   {
692     return getAlignmentFrom(alf, format, TRUE);
693   }
694
695   /*
696    * (non-Javadoc)
697    * 
698    * @see jalview.bin.JalviewLiteJsApi#getAlignment(java.lang.String,
699    * java.lang.String)
700    */
701   @Override
702   public String getAlignment(String format, String suffix)
703   {
704     return getAlignmentFrom(getDefaultTargetFrame(), format, suffix);
705   }
706
707   /*
708    * (non-Javadoc)
709    * 
710    * @see
711    * jalview.bin.JalviewLiteJsApi#getAlignmentFrom(jalview.appletgui.AlignFrame,
712    * java.lang.String, java.lang.String)
713    */
714   @Override
715   public String getAlignmentFrom(AlignFrame alf, String format,
716           String suffix)
717   {
718     try
719     {
720       boolean seqlimits = suffix.equalsIgnoreCase(TRUE);
721
722       FileFormatI theFormat = FileFormats.getInstance().forName(format);
723       String reply = new AppletFormatAdapter().formatSequences(theFormat,
724               alf.viewport.getAlignment(), seqlimits);
725       return reply;
726     } catch (IllegalArgumentException ex)
727     {
728       ex.printStackTrace();
729       return "Error retrieving alignment, possibly invalid format specifier: "
730               + format;
731     }
732   }
733
734   /*
735    * (non-Javadoc)
736    * 
737    * @see jalview.bin.JalviewLiteJsApi#loadAnnotation(java.lang.String)
738    */
739   @Override
740   public void loadAnnotation(String annotation)
741   {
742     loadAnnotationFrom(getDefaultTargetFrame(), annotation);
743   }
744
745   /*
746    * (non-Javadoc)
747    * 
748    * @see
749    * jalview.bin.JalviewLiteJsApi#loadAnnotationFrom(jalview.appletgui.AlignFrame
750    * , java.lang.String)
751    */
752   @Override
753   public void loadAnnotationFrom(AlignFrame alf, String annotation)
754   {
755     if (new AnnotationFile().annotateAlignmentView(alf.getAlignViewport(),
756             annotation, DataSourceType.PASTE))
757     {
758       alf.alignPanel.fontChanged();
759       alf.alignPanel.setScrollValues(0, 0);
760     }
761     else
762     {
763       alf.parseFeaturesFile(annotation, DataSourceType.PASTE);
764     }
765   }
766
767   /*
768    * (non-Javadoc)
769    * 
770    * @see jalview.bin.JalviewLiteJsApi#loadAnnotation(java.lang.String)
771    */
772   @Override
773   public void loadFeatures(String features, boolean autoenabledisplay)
774   {
775     loadFeaturesFrom(getDefaultTargetFrame(), features, autoenabledisplay);
776   }
777
778   /*
779    * (non-Javadoc)
780    * 
781    * @see
782    * jalview.bin.JalviewLiteJsApi#loadAnnotationFrom(jalview.appletgui.AlignFrame
783    * , java.lang.String)
784    */
785   @Override
786   public boolean loadFeaturesFrom(AlignFrame alf, String features,
787           boolean autoenabledisplay)
788   {
789     return alf.parseFeaturesFile(features, DataSourceType.PASTE,
790             autoenabledisplay);
791   }
792
793   /*
794    * (non-Javadoc)
795    * 
796    * @see jalview.bin.JalviewLiteJsApi#getFeatures(java.lang.String)
797    */
798   @Override
799   public String getFeatures(String format)
800   {
801     return getFeaturesFrom(getDefaultTargetFrame(), format);
802   }
803
804   /*
805    * (non-Javadoc)
806    * 
807    * @see
808    * jalview.bin.JalviewLiteJsApi#getFeaturesFrom(jalview.appletgui.AlignFrame,
809    * java.lang.String)
810    */
811   @Override
812   public String getFeaturesFrom(AlignFrame alf, String format)
813   {
814     return alf.outputFeatures(false, format);
815   }
816
817   /*
818    * (non-Javadoc)
819    * 
820    * @see jalview.bin.JalviewLiteJsApi#getAnnotation()
821    */
822   @Override
823   public String getAnnotation()
824   {
825     return getAnnotationFrom(getDefaultTargetFrame());
826   }
827
828   /*
829    * (non-Javadoc)
830    * 
831    * @see
832    * jalview.bin.JalviewLiteJsApi#getAnnotationFrom(jalview.appletgui.AlignFrame
833    * )
834    */
835   @Override
836   public String getAnnotationFrom(AlignFrame alf)
837   {
838     return alf.outputAnnotations(false);
839   }
840
841   /*
842    * (non-Javadoc)
843    * 
844    * @see jalview.bin.JalviewLiteJsApi#newView()
845    */
846   @Override
847   public AlignFrame newView()
848   {
849     return newViewFrom(getDefaultTargetFrame());
850   }
851
852   /*
853    * (non-Javadoc)
854    * 
855    * @see jalview.bin.JalviewLiteJsApi#newView(java.lang.String)
856    */
857   @Override
858   public AlignFrame newView(String name)
859   {
860     return newViewFrom(getDefaultTargetFrame(), name);
861   }
862
863   /*
864    * (non-Javadoc)
865    * 
866    * @see jalview.bin.JalviewLiteJsApi#newViewFrom(jalview.appletgui.AlignFrame)
867    */
868   @Override
869   public AlignFrame newViewFrom(AlignFrame alf)
870   {
871     return alf.newView(null);
872   }
873
874   /*
875    * (non-Javadoc)
876    * 
877    * @see jalview.bin.JalviewLiteJsApi#newViewFrom(jalview.appletgui.AlignFrame,
878    * java.lang.String)
879    */
880   @Override
881   public AlignFrame newViewFrom(AlignFrame alf, String name)
882   {
883     return alf.newView(name);
884   }
885
886   /*
887    * (non-Javadoc)
888    * 
889    * @see jalview.bin.JalviewLiteJsApi#loadAlignment(java.lang.String,
890    * java.lang.String)
891    */
892   @Override
893   public AlignFrame loadAlignment(String text, String title)
894   {
895     AlignmentI al = null;
896
897     try
898     {
899       FileFormatI format = new IdentifyFile().identify(text,
900               DataSourceType.PASTE);
901       al = new AppletFormatAdapter().readFile(text, DataSourceType.PASTE,
902               format);
903       if (al.getHeight() > 0)
904       {
905         return new AlignFrame(al, this, title, false);
906       }
907     } catch (IOException ex)
908     {
909       ex.printStackTrace();
910     }
911     return null;
912   }
913
914   /*
915    * (non-Javadoc)
916    * 
917    * @see jalview.bin.JalviewLiteJsApi#setMouseoverListener(java.lang.String)
918    */
919   @Override
920   public void setMouseoverListener(String listener)
921   {
922     setMouseoverListener(currentAlignFrame, listener);
923   }
924
925   private Vector<jalview.javascript.JSFunctionExec> javascriptListeners = new Vector<>();
926
927   /*
928    * (non-Javadoc)
929    * 
930    * @see
931    * jalview.bin.JalviewLiteJsApi#setMouseoverListener(jalview.appletgui.AlignFrame
932    * , java.lang.String)
933    */
934   @Override
935   public void setMouseoverListener(AlignFrame af, String listener)
936   {
937     if (listener != null)
938     {
939       listener = listener.trim();
940       if (listener.length() == 0)
941       {
942         System.err.println(
943                 "jalview Javascript error: Ignoring empty function for mouseover listener.");
944         return;
945       }
946     }
947     jalview.javascript.MouseOverListener mol = new jalview.javascript.MouseOverListener(
948             this, af, listener);
949     javascriptListeners.addElement(mol);
950     StructureSelectionManager.getStructureSelectionManager(this)
951             .addStructureViewerListener(mol);
952     if (debug)
953     {
954       System.err.println("Added a mouseover listener for "
955               + ((af == null) ? "All frames"
956                       : "Just views for "
957                               + af.getAlignViewport().getSequenceSetId()));
958       System.err.println("There are now " + javascriptListeners.size()
959               + " listeners in total.");
960     }
961   }
962
963   /*
964    * (non-Javadoc)
965    * 
966    * @see jalview.bin.JalviewLiteJsApi#setSelectionListener(java.lang.String)
967    */
968   @Override
969   public void setSelectionListener(String listener)
970   {
971     setSelectionListener(null, listener);
972   }
973
974   /*
975    * (non-Javadoc)
976    * 
977    * @see
978    * jalview.bin.JalviewLiteJsApi#setSelectionListener(jalview.appletgui.AlignFrame
979    * , java.lang.String)
980    */
981   @Override
982   public void setSelectionListener(AlignFrame af, String listener)
983   {
984     if (listener != null)
985     {
986       listener = listener.trim();
987       if (listener.length() == 0)
988       {
989         System.err.println(
990                 "jalview Javascript error: Ignoring empty function for selection listener.");
991         return;
992       }
993     }
994     jalview.javascript.JsSelectionSender mol = new jalview.javascript.JsSelectionSender(
995             this, af, listener);
996     javascriptListeners.addElement(mol);
997     StructureSelectionManager.getStructureSelectionManager(this)
998             .addSelectionListener(mol);
999     if (debug)
1000     {
1001       System.err.println("Added a selection listener for "
1002               + ((af == null) ? "All frames"
1003                       : "Just views for "
1004                               + af.getAlignViewport().getSequenceSetId()));
1005       System.err.println("There are now " + javascriptListeners.size()
1006               + " listeners in total.");
1007     }
1008   }
1009
1010   /**
1011    * Callable from javascript to register a javascript function to pass events
1012    * to a structure viewer.
1013    *
1014    * @param listener
1015    *          the name of a javascript function
1016    * @param modelSet
1017    *          a token separated list of PDB file names listened for
1018    * @see jalview.bin.JalviewLiteJsApi#setStructureListener(java.lang.String,
1019    *      java.lang.String)
1020    */
1021   @Override
1022   public void setStructureListener(String listener, String modelSet)
1023   {
1024     if (listener != null)
1025     {
1026       listener = listener.trim();
1027       if (listener.length() == 0)
1028       {
1029         System.err.println(
1030                 "jalview Javascript error: Ignoring empty function for selection listener.");
1031         return;
1032       }
1033     }
1034     MouseOverStructureListener mol = new MouseOverStructureListener(this,
1035             listener, separatorListToArray(modelSet));
1036     javascriptListeners.addElement(mol);
1037     StructureSelectionManager.getStructureSelectionManager(this)
1038             .addStructureViewerListener(mol);
1039     if (debug)
1040     {
1041       System.err.println("Added a javascript structure viewer listener '"
1042               + listener + "'");
1043       System.err.println("There are now " + javascriptListeners.size()
1044               + " listeners in total.");
1045     }
1046   }
1047
1048   /*
1049    * (non-Javadoc)
1050    * 
1051    * @see
1052    * jalview.bin.JalviewLiteJsApi#removeJavascriptListener(jalview.appletgui
1053    * .AlignFrame, java.lang.String)
1054    */
1055   @Override
1056   public void removeJavascriptListener(AlignFrame af, String listener)
1057   {
1058     if (listener != null)
1059     {
1060       listener = listener.trim();
1061       if (listener.length() == 0)
1062       {
1063         listener = null;
1064       }
1065     }
1066     boolean rprt = false;
1067     for (int ms = 0, msSize = javascriptListeners.size(); ms < msSize;)
1068     {
1069       Object lstn = javascriptListeners.elementAt(ms);
1070       JsCallBack lstner = (JsCallBack) lstn;
1071       if ((af == null || lstner.getAlignFrame() == af) && (listener == null
1072               || lstner.getListenerFunction().equals(listener)))
1073       {
1074         javascriptListeners.removeElement(lstner);
1075         msSize--;
1076         if (lstner instanceof SelectionListener)
1077         {
1078           StructureSelectionManager.getStructureSelectionManager(this)
1079                   .removeSelectionListener((SelectionListener) lstner);
1080         }
1081         else
1082         {
1083           StructureSelectionManager.getStructureSelectionManager(this)
1084                   .removeStructureViewerListener(lstner, null);
1085         }
1086         rprt = debug;
1087         if (debug)
1088         {
1089           System.err.println("Removed listener '" + listener + "'");
1090         }
1091       }
1092       else
1093       {
1094         ms++;
1095       }
1096     }
1097     if (rprt)
1098     {
1099       System.err.println("There are now " + javascriptListeners.size()
1100               + " listeners in total.");
1101     }
1102   }
1103
1104   @Override
1105   public void stop()
1106   {
1107     System.err.println("Applet " + getName() + " stop().");
1108     tidyUp();
1109   }
1110
1111   @Override
1112   public void destroy()
1113   {
1114     System.err.println("Applet " + getName() + " destroy().");
1115     tidyUp();
1116   }
1117
1118   private void tidyUp()
1119   {
1120     removeAll();
1121     if (currentAlignFrame != null && currentAlignFrame.viewport != null
1122             && currentAlignFrame.viewport.applet != null)
1123     {
1124       AlignViewport av = currentAlignFrame.viewport;
1125       currentAlignFrame.closeMenuItem_actionPerformed();
1126       av.applet = null;
1127       currentAlignFrame = null;
1128     }
1129     if (javascriptListeners != null)
1130     {
1131       while (javascriptListeners.size() > 0)
1132       {
1133         jalview.javascript.JSFunctionExec mol = javascriptListeners
1134                 .elementAt(0);
1135         javascriptListeners.removeElement(mol);
1136         if (mol instanceof SelectionListener)
1137         {
1138           StructureSelectionManager.getStructureSelectionManager(this)
1139                   .removeSelectionListener((SelectionListener) mol);
1140         }
1141         else
1142         {
1143           StructureSelectionManager.getStructureSelectionManager(this)
1144                   .removeStructureViewerListener(mol, null);
1145         }
1146         mol.jvlite = null;
1147       }
1148     }
1149     if (jsFunctionExec != null)
1150     {
1151       jsFunctionExec.stopQueue();
1152       jsFunctionExec.jvlite = null;
1153     }
1154     initialAlignFrame = null;
1155     jsFunctionExec = null;
1156     javascriptListeners = null;
1157     StructureSelectionManager.release(this);
1158   }
1159
1160   private jalview.javascript.JSFunctionExec jsFunctionExec;
1161
1162   /*
1163    * (non-Javadoc)
1164    * 
1165    * @see jalview.bin.JalviewLiteJsApi#mouseOverStructure(java.lang.String,
1166    * java.lang.String, java.lang.String)
1167    */
1168   @Override
1169   public void mouseOverStructure(final String pdbResNum, final String chain,
1170           final String pdbfile)
1171   {
1172     final StructureSelectionManagerProvider me = this;
1173     java.awt.EventQueue.invokeLater(new Runnable()
1174     {
1175       @Override
1176       public void run()
1177       {
1178         try
1179         {
1180           StructureSelectionManager.getStructureSelectionManager(me)
1181                   .mouseOverStructure(new Integer(pdbResNum).intValue(),
1182                           chain, pdbfile);
1183           if (debug)
1184           {
1185             System.err
1186                     .println("mouseOver for '" + pdbResNum + "' in chain '"
1187                             + chain + "' in structure '" + pdbfile + "'");
1188           }
1189         } catch (NumberFormatException e)
1190         {
1191           System.err.println("Ignoring invalid residue number string '"
1192                   + pdbResNum + "'");
1193         }
1194
1195       }
1196     });
1197   }
1198
1199   /*
1200    * (non-Javadoc)
1201    * 
1202    * @see
1203    * jalview.bin.JalviewLiteJsApi#scrollViewToIn(jalview.appletgui.AlignFrame,
1204    * java.lang.String, java.lang.String)
1205    */
1206   @Override
1207   public void scrollViewToIn(final AlignFrame alf, final String topRow,
1208           final String leftHandColumn)
1209   {
1210     java.awt.EventQueue.invokeLater(new Runnable()
1211     {
1212       @Override
1213       public void run()
1214       {
1215         try
1216         {
1217           alf.scrollTo(new Integer(topRow).intValue(),
1218                   new Integer(leftHandColumn).intValue());
1219
1220         } catch (Exception ex)
1221         {
1222           System.err.println("Couldn't parse integer arguments (topRow='"
1223                   + topRow + "' and leftHandColumn='" + leftHandColumn
1224                   + "')");
1225           ex.printStackTrace();
1226         }
1227       }
1228     });
1229   }
1230
1231   /*
1232    * (non-Javadoc)
1233    * 
1234    * @see
1235    * jalview.javascript.JalviewLiteJsApi#scrollViewToRowIn(jalview.appletgui
1236    * .AlignFrame, java.lang.String)
1237    */
1238   @Override
1239   public void scrollViewToRowIn(final AlignFrame alf, final String topRow)
1240   {
1241
1242     java.awt.EventQueue.invokeLater(new Runnable()
1243     {
1244       @Override
1245       public void run()
1246       {
1247         try
1248         {
1249           alf.scrollToRow(new Integer(topRow).intValue());
1250
1251         } catch (Exception ex)
1252         {
1253           System.err.println("Couldn't parse integer arguments (topRow='"
1254                   + topRow + "')");
1255           ex.printStackTrace();
1256         }
1257
1258       }
1259     });
1260   }
1261
1262   /*
1263    * (non-Javadoc)
1264    * 
1265    * @see
1266    * jalview.javascript.JalviewLiteJsApi#scrollViewToColumnIn(jalview.appletgui
1267    * .AlignFrame, java.lang.String)
1268    */
1269   @Override
1270   public void scrollViewToColumnIn(final AlignFrame alf,
1271           final String leftHandColumn)
1272   {
1273     java.awt.EventQueue.invokeLater(new Runnable()
1274     {
1275
1276       @Override
1277       public void run()
1278       {
1279         try
1280         {
1281           alf.scrollToColumn(new Integer(leftHandColumn).intValue());
1282
1283         } catch (Exception ex)
1284         {
1285           System.err.println(
1286                   "Couldn't parse integer arguments (leftHandColumn='"
1287                           + leftHandColumn + "')");
1288           ex.printStackTrace();
1289         }
1290       }
1291     });
1292
1293   }
1294
1295   // //////////////////////////////////////////////
1296   // //////////////////////////////////////////////
1297
1298   public static int lastFrameX = 200;
1299
1300   public static int lastFrameY = 200;
1301
1302   boolean fileFound = true;
1303
1304   String file = "No file";
1305
1306   String file2 = null;
1307
1308   Button launcher = new Button(
1309           MessageManager.getString("label.start_jalview"));
1310
1311   /**
1312    * The currentAlignFrame is static, it will change if and when the user
1313    * selects a new window. Note that it will *never* point back to the embedded
1314    * AlignFrame if the applet is started as embedded on the page and then
1315    * afterwards a new view is created.
1316    */
1317   public AlignFrame currentAlignFrame = null;
1318
1319   /**
1320    * This is the first frame to be displayed, and does not change. API calls
1321    * will default to this instance if currentAlignFrame is null.
1322    */
1323   AlignFrame initialAlignFrame = null;
1324
1325   boolean embedded = false;
1326
1327   private boolean checkForJmol = true;
1328
1329   private boolean checkedForJmol = false; // ensure we don't check for jmol
1330
1331   // every time the app is re-inited
1332
1333   public boolean jmolAvailable = false;
1334
1335   private boolean alignPdbStructures = false;
1336
1337   /**
1338    * use an external structure viewer exclusively (no jmols or mc_views will be
1339    * opened by JalviewLite itself)
1340    */
1341   public boolean useXtrnalSviewer = false;
1342
1343   public JalviewAppLoader appLoader;
1344
1345   public AlignFrame loaderFrame;
1346
1347   public static boolean debug = false;
1348
1349   static String builddate = null, version = null, installation = null;
1350
1351   private static void initBuildDetails()
1352   {
1353     if (builddate == null)
1354     {
1355       builddate = "unknown";
1356       version = "test";
1357       installation = "applet";
1358       java.net.URL url = JalviewLite.class
1359               .getResource("/.build_properties");
1360       if (url != null)
1361       {
1362         try
1363         {
1364           BufferedReader reader = new BufferedReader(
1365                   new InputStreamReader(url.openStream()));
1366           String line;
1367           while ((line = reader.readLine()) != null)
1368           {
1369             if (line.indexOf("VERSION") > -1)
1370             {
1371               version = line.substring(line.indexOf("=") + 1);
1372             }
1373             if (line.indexOf("BUILD_DATE") > -1)
1374             {
1375               builddate = line.substring(line.indexOf("=") + 1);
1376             }
1377             if (line.indexOf("INSTALLATION") > -1)
1378             {
1379               installation = line.substring(line.indexOf("=") + 1);
1380             }
1381           }
1382         } catch (Exception ex)
1383         {
1384           ex.printStackTrace();
1385         }
1386       }
1387     }
1388   }
1389
1390   public static String getBuildDate()
1391   {
1392     initBuildDetails();
1393     return builddate;
1394   }
1395
1396   public static String getInstallation()
1397   {
1398     initBuildDetails();
1399     return installation;
1400   }
1401
1402   public static String getVersion()
1403   {
1404     initBuildDetails();
1405     return version;
1406   }
1407
1408   // public JSObject scriptObject = null;
1409
1410   /**
1411    * init method for Jalview Applet
1412    */
1413   @Override
1414   public void init()
1415   {
1416     debug = TRUE.equalsIgnoreCase(getParameter("debug"));
1417     try
1418     {
1419       if (debug)
1420       {
1421         System.err.println("Applet context is '"
1422                 + getAppletContext().getClass().toString() + "'");
1423       }
1424       JSObject scriptObject = JSObject.getWindow(this);
1425       if (debug && scriptObject != null)
1426       {
1427         System.err.println("Applet has Javascript callback support.");
1428       }
1429
1430     } catch (Exception ex)
1431     {
1432       System.err.println(
1433               "Warning: No JalviewLite javascript callbacks available.");
1434       if (debug)
1435       {
1436         ex.printStackTrace();
1437       }
1438     }
1439
1440     if (debug)
1441     {
1442       System.err.println("JalviewLite Version " + getVersion());
1443       System.err.println("Build Date : " + getBuildDate());
1444       System.err.println("Installation : " + getInstallation());
1445     }
1446     String externalsviewer = getParameter("externalstructureviewer");
1447     if (externalsviewer != null)
1448     {
1449       useXtrnalSviewer = externalsviewer.trim().toLowerCase().equals(TRUE);
1450     }
1451     /**
1452      * if true disable the check for jmol
1453      */
1454     String chkforJmol = getParameter("nojmol");
1455     if (chkforJmol != null)
1456     {
1457       checkForJmol = !chkforJmol.equals(TRUE);
1458     }
1459     /**
1460      * get the separator parameter if present
1461      */
1462     String sep = getParameter("separator");
1463     if (sep != null)
1464     {
1465       if (sep.length() > 0)
1466       {
1467         separator = sep;
1468         if (debug)
1469         {
1470           System.err.println("Separator set to '" + separator + "'");
1471         }
1472       }
1473       else
1474       {
1475         throw new Error(MessageManager
1476                 .getString("error.invalid_separator_parameter"));
1477       }
1478     }
1479     int r = 255;
1480     int g = 255;
1481     int b = 255;
1482     String param = getParameter("RGB");
1483
1484     if (param != null)
1485     {
1486       try
1487       {
1488         r = Integer.parseInt(param.substring(0, 2), 16);
1489         g = Integer.parseInt(param.substring(2, 4), 16);
1490         b = Integer.parseInt(param.substring(4, 6), 16);
1491       } catch (Exception ex)
1492       {
1493         r = 255;
1494         g = 255;
1495         b = 255;
1496       }
1497     }
1498     param = getParameter("label");
1499     if (param != null)
1500     {
1501       launcher.setLabel(param);
1502     }
1503
1504     setBackground(new Color(r, g, b));
1505
1506     file = getParameter("file");
1507
1508     if (file == null)
1509     {
1510       // Maybe the sequences are added as parameters
1511       StringBuffer data = new StringBuffer("PASTE");
1512       int i = 1;
1513       while ((file = getParameter("sequence" + i)) != null)
1514       {
1515         data.append(file.toString() + "\n");
1516         i++;
1517       }
1518       if (data.length() > 5)
1519       {
1520         file = data.toString();
1521       }
1522     }
1523     if (getDefaultParameter("enableSplitFrame", true))
1524     {
1525       file2 = getParameter("file2");
1526     }
1527
1528     embedded = TRUE.equalsIgnoreCase(getParameter("embedded"));
1529     if (embedded)
1530     {
1531       LoadingThread loader = new LoadingThread(file, file2, this);
1532       loader.start();
1533     }
1534     else if (file != null)
1535     {
1536       /*
1537        * Start the applet immediately or show a button to start it
1538        */
1539       if (FALSE.equalsIgnoreCase(getParameter("showbutton")))
1540       {
1541         LoadingThread loader = new LoadingThread(file, file2, this);
1542         loader.start();
1543       }
1544       else
1545       {
1546         add(launcher);
1547         launcher.addActionListener(new java.awt.event.ActionListener()
1548         {
1549           @Override
1550           public void actionPerformed(ActionEvent e)
1551           {
1552             LoadingThread loader = new LoadingThread(file, file2,
1553                     JalviewLite.this);
1554             loader.start();
1555           }
1556         });
1557       }
1558     }
1559     else
1560     {
1561       // jalview initialisation with no alignment. loadAlignment() method can
1562       // still be called to open new alignments.
1563       file = "NO FILE";
1564       fileFound = false;
1565       callInitCallback();
1566     }
1567   }
1568
1569   private void initLiveConnect()
1570   {
1571     // try really hard to get the liveConnect thing working
1572     boolean notFailed = false;
1573     int tries = 0;
1574     while (!notFailed && tries < 10)
1575     {
1576       if (tries > 0)
1577       {
1578         System.err.println("LiveConnect request thread going to sleep.");
1579       }
1580       try
1581       {
1582         Thread.sleep(700 * (1 + tries));
1583       } catch (InterruptedException q)
1584       {
1585       }
1586       ;
1587       if (tries++ > 0)
1588       {
1589         System.err.println("LiveConnect request thread woken up.");
1590       }
1591       try
1592       {
1593         JSObject scriptObject = JSObject.getWindow(this);
1594         if (scriptObject.eval("navigator") != null)
1595         {
1596           notFailed = true;
1597         }
1598       } catch (Exception jsex)
1599       {
1600         System.err.println("Attempt " + tries
1601                 + " to access LiveConnect javascript failed.");
1602       }
1603     }
1604   }
1605
1606   private void callInitCallback()
1607   {
1608     String initjscallback = getParameter("oninit");
1609     if (initjscallback == null)
1610     {
1611       return;
1612     }
1613     initjscallback = initjscallback.trim();
1614     if (initjscallback.length() > 0)
1615     {
1616       JSObject scriptObject = null;
1617       try
1618       {
1619         scriptObject = JSObject.getWindow(this);
1620       } catch (Exception ex)
1621       {
1622       }
1623       ;
1624       // try really hard to let the browser plugin know we want liveconnect
1625       initLiveConnect();
1626
1627       if (scriptObject != null)
1628       {
1629         try
1630         {
1631           // do onInit with the JS executor thread
1632           new JSFunctionExec(this).executeJavascriptFunction(true,
1633                   initjscallback, null,
1634                   "Calling oninit callback '" + initjscallback + "'.");
1635         } catch (Exception e)
1636         {
1637           System.err.println("Exception when executing _oninit callback '"
1638                   + initjscallback + "'.");
1639           e.printStackTrace();
1640         }
1641       }
1642       else
1643       {
1644         System.err.println("Not executing _oninit callback '"
1645                 + initjscallback + "' - no scripting allowed.");
1646       }
1647     }
1648   }
1649
1650   /**
1651    * Initialises and displays a new java.awt.Frame
1652    * 
1653    * @param frame
1654    *          java.awt.Frame to be displayed
1655    * @param title
1656    *          title of new frame
1657    * @param width
1658    *          width if new frame
1659    * @param height
1660    *          height of new frame
1661    */
1662   public static void addFrame(final Frame frame, String title, int width,
1663           int height)
1664   {
1665     frame.setLocation(lastFrameX, lastFrameY);
1666     lastFrameX += 40;
1667     lastFrameY += 40;
1668     frame.setSize(width, height);
1669     frame.setTitle(title);
1670     frame.addWindowListener(new WindowAdapter()
1671     {
1672       @Override
1673       public void windowClosing(WindowEvent e)
1674       {
1675         if (frame instanceof AlignFrame)
1676         {
1677           AlignViewport vp = ((AlignFrame) frame).viewport;
1678           ((AlignFrame) frame).closeMenuItem_actionPerformed();
1679           if (vp.applet.currentAlignFrame == frame)
1680           {
1681             vp.applet.currentAlignFrame = null;
1682           }
1683           vp.applet = null;
1684           vp = null;
1685
1686         }
1687         lastFrameX -= 40;
1688         lastFrameY -= 40;
1689         if (frame instanceof EmbmenuFrame)
1690         {
1691           ((EmbmenuFrame) frame).destroyMenus();
1692         }
1693         frame.setMenuBar(null);
1694         frame.dispose();
1695       }
1696
1697       @Override
1698       public void windowActivated(WindowEvent e)
1699       {
1700         if (frame instanceof AlignFrame)
1701         {
1702           ((AlignFrame) frame).viewport.applet.currentAlignFrame = (AlignFrame) frame;
1703           if (debug)
1704           {
1705             System.err.println("Activated window " + frame);
1706           }
1707         }
1708         // be good.
1709         super.windowActivated(e);
1710       }
1711       /*
1712        * Probably not necessary to do this - see TODO above. (non-Javadoc)
1713        * 
1714        * @see
1715        * java.awt.event.WindowAdapter#windowDeactivated(java.awt.event.WindowEvent
1716        * )
1717        * 
1718        * public void windowDeactivated(WindowEvent e) { if (currentAlignFrame ==
1719        * frame) { currentAlignFrame = null; if (debug) {
1720        * System.err.println("Deactivated window "+frame); } }
1721        * super.windowDeactivated(e); }
1722        */
1723     });
1724     frame.setVisible(true);
1725   }
1726
1727   /**
1728    * This paints the background surrounding the "Launch Jalview button" <br>
1729    * <br>
1730    * If file given in parameter not found, displays error message
1731    * 
1732    * @param g
1733    *          graphics context
1734    */
1735   @Override
1736   public void paint(Graphics g)
1737   {
1738     if (!fileFound)
1739     {
1740       g.setColor(new Color(200, 200, 200));
1741       g.setColor(Color.cyan);
1742       g.fillRect(0, 0, getSize().width, getSize().height);
1743       g.setColor(Color.red);
1744       g.drawString(
1745               MessageManager.getString("label.jalview_cannot_open_file"), 5,
1746               15);
1747       g.drawString("\"" + file + "\"", 5, 30);
1748     }
1749     else if (embedded)
1750     {
1751       g.setColor(Color.black);
1752       g.setFont(new Font("Arial", Font.BOLD, 24));
1753       g.drawString(MessageManager.getString("label.jalview_applet"), 50,
1754               getSize().height / 2 - 30);
1755       g.drawString(MessageManager.getString("label.loading_data") + "...",
1756               50, getSize().height / 2);
1757     }
1758   }
1759
1760   /**
1761    * get all components associated with the applet of the given type
1762    * 
1763    * @param class1
1764    * @return
1765    */
1766   public Vector getAppletWindow(Class class1)
1767   {
1768     Vector wnds = new Vector();
1769     Component[] cmp = getComponents();
1770     if (cmp != null)
1771     {
1772       for (int i = 0; i < cmp.length; i++)
1773       {
1774         if (class1.isAssignableFrom(cmp[i].getClass()))
1775         {
1776           wnds.addElement(cmp);
1777         }
1778       }
1779     }
1780     return wnds;
1781   }
1782
1783   class LoadJmolThread extends Thread
1784   {
1785     private boolean running = false;
1786
1787     @Override
1788     public void run()
1789     {
1790       if (running || checkedForJmol)
1791       {
1792         return;
1793       }
1794       running = true;
1795       if (checkForJmol)
1796       {
1797         try
1798         {
1799           if (!System.getProperty("java.version").startsWith("1.1"))
1800           {
1801             Class.forName("org.jmol.adapter.smarter.SmarterJmolAdapter");
1802             jmolAvailable = true;
1803           }
1804           if (!jmolAvailable)
1805           {
1806             System.out.println(
1807                     "Jmol not available - Using mc_view for structures");
1808           }
1809         } catch (java.lang.ClassNotFoundException ex)
1810         {
1811         }
1812       }
1813       else
1814       {
1815         jmolAvailable = false;
1816         if (debug)
1817         {
1818           System.err.println(
1819                   "Skipping Jmol check. Will use mc_view (probably)");
1820         }
1821       }
1822       checkedForJmol = true;
1823       running = false;
1824     }
1825
1826     public boolean notFinished()
1827     {
1828       return running || !checkedForJmol;
1829     }
1830   }
1831
1832   class LoadingThread extends Thread
1833   {
1834     /**
1835      * State variable: protocol for access to file source
1836      */
1837     DataSourceType protocol;
1838
1839     String _file; // alignment file or URL spec
1840
1841     String _file2; // second alignment file or URL spec
1842
1843     JalviewLite applet;
1844
1845     public void dbgMsg(String msg)
1846     {
1847       if (JalviewLite.debug)
1848       {
1849         System.err.println(msg);
1850       }
1851     }
1852
1853     /**
1854      * update the protocol state variable for accessing the datasource located
1855      * by file.
1856      * 
1857      * @param path
1858      * @return possibly updated datasource string
1859      */
1860     public String resolveFileProtocol(String path)
1861     {
1862
1863       String[] ret = new String[] { path };
1864       protocol = JalviewAppLoader.resolveFileProtocol(applet, ret);
1865       return ret[0];
1866     }
1867
1868     public LoadingThread(String file, String file2, JalviewLite _applet)
1869     {
1870       this._file = file;
1871       this._file2 = file2;
1872       applet = _applet;
1873     }
1874
1875     @Override
1876     public void run()
1877     {
1878       LoadJmolThread jmolchecker = new LoadJmolThread();
1879       jmolchecker.start();
1880       while (jmolchecker.notFinished())
1881       {
1882         // wait around until the Jmol check is complete.
1883         try
1884         {
1885           Thread.sleep(2);
1886         } catch (Exception e)
1887         {
1888         }
1889       }
1890       startLoading();
1891       // applet.callInitCallback();
1892     }
1893
1894     /**
1895      * Load the alignment and any related files as specified by applet
1896      * parameters
1897      */
1898     private void startLoading()
1899     {
1900       dbgMsg("Loading thread started with:\n>>file\n" + _file
1901               + ">>endfile");
1902
1903       dbgMsg("Loading started.");
1904
1905       AlignFrame newAlignFrame = readAlignment(_file);
1906       AlignFrame newAlignFrame2 = readAlignment(_file2);
1907       if (newAlignFrame != null)
1908       {
1909         addToDisplay(newAlignFrame, newAlignFrame2);
1910         applet.loaderFrame = newAlignFrame;
1911         appLoader.load(applet);
1912       }
1913       else
1914       {
1915         fileFound = false;
1916         applet.remove(launcher);
1917         applet.repaint();
1918       }
1919       callInitCallback();
1920     }
1921
1922     /**
1923      * Add an AlignFrame to the display; or if two are provided, a SplitFrame.
1924      * 
1925      * @param af
1926      * @param af2
1927      */
1928     public void addToDisplay(AlignFrame af, AlignFrame af2)
1929     {
1930       if (af2 != null)
1931       {
1932         AlignmentI al1 = af.viewport.getAlignment();
1933         AlignmentI al2 = af2.viewport.getAlignment();
1934         AlignmentI cdna = al1.isNucleotide() ? al1 : al2;
1935         AlignmentI prot = al1.isNucleotide() ? al2 : al1;
1936         if (AlignmentUtils.mapProteinAlignmentToCdna(prot, cdna))
1937         {
1938           al2.alignAs(al1);
1939           SplitFrame sf = new SplitFrame(af, af2);
1940           sf.addToDisplay(embedded, JalviewLite.this);
1941           return;
1942         }
1943         else
1944         {
1945           String msg = "Could not map any sequence in " + af2.getTitle()
1946                   + " as "
1947                   + (al1.isNucleotide() ? "protein product" : "cDNA")
1948                   + " for " + af.getTitle();
1949           System.err.println(msg);
1950         }
1951       }
1952
1953       af.addToDisplay(embedded);
1954     }
1955
1956     /**
1957      * Read the alignment file (from URL, text 'paste', or archive by
1958      * classloader).
1959      * 
1960      * @return
1961      */
1962     protected AlignFrame readAlignment(String fileParam)
1963     {
1964       if (fileParam == null)
1965       {
1966         return null;
1967       }
1968       String resolvedFile = resolveFileProtocol(fileParam);
1969       AlignmentI al = null;
1970       try
1971       {
1972         FileFormatI format = new IdentifyFile().identify(resolvedFile,
1973                 protocol);
1974         dbgMsg("File identified as '" + format + "'");
1975         al = new AppletFormatAdapter().readFile(resolvedFile, protocol,
1976                 format);
1977         if ((al != null) && (al.getHeight() > 0))
1978         {
1979           dbgMsg("Successfully loaded file.");
1980           al.setDataset(null);
1981           AlignFrame newAlignFrame = new AlignFrame(al, applet,
1982                   resolvedFile, embedded, false);
1983           newAlignFrame.setTitle(resolvedFile);
1984           if (initialAlignFrame == null)
1985           {
1986             initialAlignFrame = newAlignFrame;
1987           }
1988           // update the focus.
1989           currentAlignFrame = newAlignFrame;
1990
1991           if (protocol == DataSourceType.PASTE)
1992           {
1993             newAlignFrame.setTitle(MessageManager
1994                     .formatMessage("label.sequences_from", new Object[]
1995                     { applet.getDocumentBase().toString() }));
1996           }
1997
1998           newAlignFrame.statusBar.setText(MessageManager.formatMessage(
1999                   "label.successfully_loaded_file", new Object[]
2000                   { resolvedFile }));
2001
2002           return newAlignFrame;
2003         }
2004       } catch (java.io.IOException ex)
2005       {
2006         dbgMsg("File load exception.");
2007         ex.printStackTrace();
2008         if (debug)
2009         {
2010           try
2011           {
2012             FileParse fp = new FileParse(resolvedFile, protocol);
2013             String ln = null;
2014             dbgMsg(">>>Dumping contents of '" + resolvedFile + "' " + "("
2015                     + protocol + ")");
2016             while ((ln = fp.nextLine()) != null)
2017             {
2018               dbgMsg(ln);
2019             }
2020             dbgMsg(">>>Dump finished.");
2021           } catch (Exception e)
2022           {
2023             System.err.println(
2024                     "Exception when trying to dump the content of the file parameter.");
2025             e.printStackTrace();
2026           }
2027         }
2028       }
2029       return null;
2030     }
2031
2032   }
2033
2034   /**
2035    * @return the default alignFrame acted on by the public applet methods. May
2036    *         return null with an error message on System.err indicating the
2037    *         fact.
2038    */
2039   public AlignFrame getDefaultTargetFrame()
2040   {
2041     if (currentAlignFrame != null)
2042     {
2043       return currentAlignFrame;
2044     }
2045     if (initialAlignFrame != null)
2046     {
2047       return initialAlignFrame;
2048     }
2049     System.err.println(
2050             "Implementation error: Jalview Applet API cannot work out which AlignFrame to use.");
2051     return null;
2052   }
2053
2054   /**
2055    * separator used for separatorList
2056    */
2057   protected String separator = "" + ((char) 0x00AC); // the default used to be
2058                                                      // '|' but many sequence
2059                                                      // IDS include pipes.
2060
2061   /**
2062    * set to enable the URL based javascript execution mechanism
2063    */
2064   public boolean jsfallbackEnabled = false;
2065
2066   /**
2067    * parse the string into a list
2068    * 
2069    * @param list
2070    * @return elements separated by separator
2071    */
2072   public String[] separatorListToArray(String list)
2073   {
2074     return JalviewAppLoader.separatorListToArray(list, separator);
2075   }
2076
2077   /**
2078    * concatenate the list with separator
2079    * 
2080    * @param list
2081    * @return concatenated string
2082    */
2083   public String arrayToSeparatorList(String[] list)
2084   {
2085     return arrayToSeparatorList(list, separator);
2086   }
2087
2088   /**
2089    * concatenate the list with separator
2090    * 
2091    * @param list
2092    * @param separator
2093    * @return concatenated string
2094    */
2095   public static String arrayToSeparatorList(String[] list, String separator)
2096   {
2097     // TODO use StringUtils version
2098     StringBuffer v = new StringBuffer();
2099     if (list != null && list.length > 0)
2100     {
2101       for (int i = 0, iSize = list.length; i < iSize; i++)
2102       {
2103         if (list[i] != null)
2104         {
2105           if (i > 0)
2106           {
2107             v.append(separator);
2108           }
2109           v.append(list[i]);
2110         }
2111       }
2112       if (debug)
2113       {
2114         System.err
2115                 .println("Returning '" + separator + "' separated List:\n");
2116         System.err.println(v);
2117       }
2118       return v.toString();
2119     }
2120     if (debug)
2121     {
2122       System.err.println(
2123               "Returning empty '" + separator + "' separated List\n");
2124     }
2125     return "" + separator;
2126   }
2127
2128   /*
2129    * (non-Javadoc)
2130    * 
2131    * @see jalview.bin.JalviewLiteJsApi#getFeatureGroups()
2132    */
2133   @Override
2134   public String getFeatureGroups()
2135   {
2136     String lst = arrayToSeparatorList(
2137             getDefaultTargetFrame().getFeatureGroups());
2138     return lst;
2139   }
2140
2141   /*
2142    * (non-Javadoc)
2143    * 
2144    * @see
2145    * jalview.bin.JalviewLiteJsApi#getFeatureGroupsOn(jalview.appletgui.AlignFrame
2146    * )
2147    */
2148   @Override
2149   public String getFeatureGroupsOn(AlignFrame alf)
2150   {
2151     String lst = arrayToSeparatorList(alf.getFeatureGroups());
2152     return lst;
2153   }
2154
2155   /*
2156    * (non-Javadoc)
2157    * 
2158    * @see jalview.bin.JalviewLiteJsApi#getFeatureGroupsOfState(boolean)
2159    */
2160   @Override
2161   public String getFeatureGroupsOfState(boolean visible)
2162   {
2163     return arrayToSeparatorList(
2164             getDefaultTargetFrame().getFeatureGroupsOfState(visible));
2165   }
2166
2167   /*
2168    * (non-Javadoc)
2169    * 
2170    * @see
2171    * jalview.bin.JalviewLiteJsApi#getFeatureGroupsOfStateOn(jalview.appletgui
2172    * .AlignFrame, boolean)
2173    */
2174   @Override
2175   public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible)
2176   {
2177     return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible));
2178   }
2179
2180   /*
2181    * (non-Javadoc)
2182    * 
2183    * @see jalview.bin.JalviewLiteJsApi#setFeatureGroupStateOn(jalview.appletgui.
2184    * AlignFrame, java.lang.String, boolean)
2185    */
2186   @Override
2187   public void setFeatureGroupStateOn(final AlignFrame alf,
2188           final String groups, boolean state)
2189   {
2190     final boolean st = state;// !(state==null || state.equals("") ||
2191     // state.toLowerCase().equals("false"));
2192     java.awt.EventQueue.invokeLater(new Runnable()
2193     {
2194       @Override
2195       public void run()
2196       {
2197         alf.setFeatureGroupState(separatorListToArray(groups), st);
2198       }
2199     });
2200   }
2201
2202   /*
2203    * (non-Javadoc)
2204    * 
2205    * @see jalview.bin.JalviewLiteJsApi#setFeatureGroupState(java.lang.String,
2206    * boolean)
2207    */
2208   @Override
2209   public void setFeatureGroupState(String groups, boolean state)
2210   {
2211     setFeatureGroupStateOn(getDefaultTargetFrame(), groups, state);
2212   }
2213
2214   /*
2215    * (non-Javadoc)
2216    * 
2217    * @see jalview.bin.JalviewLiteJsApi#getSeparator()
2218    */
2219   @Override
2220   public String getSeparator()
2221   {
2222     return separator;
2223   }
2224
2225   /*
2226    * (non-Javadoc)
2227    * 
2228    * @see jalview.bin.JalviewLiteJsApi#setSeparator(java.lang.String)
2229    */
2230   @Override
2231   public void setSeparator(String separator)
2232   {
2233     if (separator == null || separator.length() < 1)
2234     {
2235       // reset to default
2236       separator = "" + ((char) 0x00AC);
2237     }
2238     this.separator = separator;
2239     if (debug)
2240     {
2241       System.err.println("Default Separator now: '" + separator + "'");
2242     }
2243   }
2244
2245   /**
2246    * get boolean value of applet parameter 'name' and return default if
2247    * parameter is not set
2248    * 
2249    * @param name
2250    *          name of paremeter
2251    * @param def
2252    *          the value to return otherwise
2253    * @return true or false
2254    */
2255   @Override
2256   public boolean getDefaultParameter(String name, boolean def)
2257   {
2258     String stn;
2259     if ((stn = getParameter(name)) == null)
2260     {
2261       return def;
2262     }
2263     if (TRUE.equalsIgnoreCase(stn))
2264     {
2265       return true;
2266     }
2267     return false;
2268   }
2269
2270   /*
2271    * (non-Javadoc)
2272    * 
2273    * @see jalview.bin.JalviewLiteJsApi#addPdbFile(jalview.appletgui.AlignFrame,
2274    * java.lang.String, java.lang.String, java.lang.String)
2275    */
2276   @Override
2277   public boolean addPdbFile(AlignFrame alFrame, String sequenceId,
2278           String pdbEntryString, String pdbFile)
2279   {
2280     return alFrame.addPdbFile(sequenceId, pdbEntryString, pdbFile);
2281   }
2282
2283   @Override
2284   public void setAlignPdbStructures(boolean alignPdbStructures)
2285   {
2286     this.alignPdbStructures = alignPdbStructures;
2287   }
2288
2289   public boolean isAlignPdbStructures()
2290   {
2291     return alignPdbStructures;
2292   }
2293
2294   @Override
2295   public void start()
2296   {
2297     // callInitCallback();
2298   }
2299
2300   private Hashtable<String, long[]> jshashes = new Hashtable<>();
2301
2302   private Hashtable<String, Hashtable<String, String[]>> jsmessages = new Hashtable<>();
2303
2304   public void setJsMessageSet(String messageclass, String viewId,
2305           String[] colcommands)
2306   {
2307     Hashtable<String, String[]> msgset = jsmessages.get(messageclass);
2308     if (msgset == null)
2309     {
2310       msgset = new Hashtable<>();
2311       jsmessages.put(messageclass, msgset);
2312     }
2313     msgset.put(viewId, colcommands);
2314     long[] l = new long[colcommands.length];
2315     for (int i = 0; i < colcommands.length; i++)
2316     {
2317       l[i] = colcommands[i].hashCode();
2318     }
2319     jshashes.put(messageclass + "|" + viewId, l);
2320   }
2321
2322   /*
2323    * (non-Javadoc)
2324    * 
2325    * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String,
2326    * java.lang.String)
2327    */
2328   @Override
2329   public String getJsMessage(String messageclass, String viewId)
2330   {
2331     Hashtable<String, String[]> msgset = jsmessages.get(messageclass);
2332     if (msgset != null)
2333     {
2334       String[] msgs = msgset.get(viewId);
2335       if (msgs != null)
2336       {
2337         for (int i = 0; i < msgs.length; i++)
2338         {
2339           if (msgs[i] != null)
2340           {
2341             String m = msgs[i];
2342             msgs[i] = null;
2343             return m;
2344           }
2345         }
2346       }
2347     }
2348     return "";
2349   }
2350
2351   public boolean isJsMessageSetChanged(String string, String string2,
2352           String[] colcommands)
2353   {
2354     long[] l = jshashes.get(string + "|" + string2);
2355     if (l == null && colcommands != null)
2356     {
2357       return true;
2358     }
2359     for (int i = 0; i < colcommands.length; i++)
2360     {
2361       if (l[i] != colcommands[i].hashCode())
2362       {
2363         return true;
2364       }
2365     }
2366     return false;
2367   }
2368
2369   private Vector jsExecQueue = new Vector();
2370
2371   public Vector getJsExecQueue()
2372   {
2373     return jsExecQueue;
2374   }
2375
2376   public void setExecutor(JSFunctionExec jsFunctionExec2)
2377   {
2378     jsFunctionExec = jsFunctionExec2;
2379   }
2380
2381   /**
2382    * return the given colour value parameter or the given default if parameter
2383    * not given
2384    * 
2385    * @param colparam
2386    * @param defcolour
2387    * @return
2388    */
2389   public Color getDefaultColourParameter(String colparam, Color defcolour)
2390   {
2391     String colprop = getParameter(colparam);
2392     if (colprop == null || colprop.trim().length() == 0)
2393     {
2394       return defcolour;
2395     }
2396     Color col = ColorUtils.parseColourString(colprop);
2397     if (col == null)
2398     {
2399       System.err.println("Couldn't parse '" + colprop + "' as a colour for "
2400               + colparam);
2401     }
2402     return (col == null) ? defcolour : col;
2403   }
2404
2405   public void openJalviewHelpUrl()
2406   {
2407     String helpUrl = getParameter("jalviewhelpurl");
2408     if (helpUrl == null || helpUrl.trim().length() < 5)
2409     {
2410       helpUrl = "http://www.jalview.org/help.html";
2411     }
2412     showURL(helpUrl, "HELP");
2413   }
2414
2415   /**
2416    * open a URL in the browser - resolving it according to relative refs and
2417    * coping with javascript: protocol if necessary.
2418    * 
2419    * @param url
2420    * @param target
2421    */
2422   public void showURL(String url, String target)
2423   {
2424     try
2425     {
2426       if (url.indexOf(":") == -1)
2427       {
2428         // TODO: verify (Bas Vroling bug) prepend codebase or server URL to
2429         // form valid URL
2430         // Should really use docbase, not codebase.
2431         URL prepend;
2432         url = JalviewAppLoader.resolveUrlForLocalOrAbsolute(url,
2433                 prepend = getDefaultParameter("resolvetocodebase", false)
2434                         ? getCodeBase()
2435                         : getDocumentBase());
2436         if (debug)
2437         {
2438           System.err.println("Show url (prepended " + prepend
2439                   + " - toggle resolvetocodebase if code/docbase resolution is wrong): "
2440                   + url);
2441         }
2442       }
2443       else
2444       {
2445         if (debug)
2446         {
2447           System.err.println("Show url: " + url);
2448         }
2449       }
2450       if (url.indexOf("javascript:") == 0)
2451       {
2452         // no target for the javascript context
2453         getAppletContext().showDocument(new java.net.URL(url));
2454       }
2455       else
2456       {
2457         getAppletContext().showDocument(new java.net.URL(url), target);
2458       }
2459     } catch (Exception ex)
2460     {
2461       ex.printStackTrace();
2462     }
2463   }
2464
2465   @Override
2466   public AlignViewportI getViewport()
2467   {
2468     return loaderFrame.getAlignViewport();
2469   }
2470
2471   @Override
2472   public void newStructureView(PDBEntry pdb, SequenceI[] seqs,
2473           String[] chains, DataSourceType protocol)
2474   {
2475     loaderFrame.newStructureView(this, pdb, seqs, chains,
2476             protocol);
2477   }
2478
2479   @Override
2480   public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs,
2481           String[][] chains, String[] protocols)
2482   {
2483     loaderFrame.alignedStructureView(this, pdb, seqs, chains, protocols);
2484   }
2485
2486   @Override
2487   public void updateForAnnotations()
2488   {
2489     loaderFrame.alignPanel.fontChanged();
2490     loaderFrame.alignPanel.setScrollValues(0, 0);
2491   }
2492
2493   @Override
2494   public void setFeatureGroupState(String[] groups, boolean state)
2495   {
2496     loaderFrame.setFeatureGroupState(groups, state);
2497   }
2498
2499   @Override
2500   public boolean parseFeaturesFile(String param, DataSourceType protocol)
2501   {
2502     return loaderFrame.parseFeaturesFile(param, protocol);
2503   }
2504
2505   @Override
2506   public void newFeatureSettings()
2507   {
2508     getViewport().setShowSequenceFeatures(true);
2509     new FeatureSettings(loaderFrame.alignPanel);
2510   }
2511
2512   @Override
2513   public boolean loadScoreFile(String sScoreFile) throws IOException
2514   {
2515     return loaderFrame.loadScoreFile(sScoreFile);
2516   }
2517
2518   @Override
2519   public void loadTree(NewickFile tree, String treeFile) throws IOException
2520   {
2521     loaderFrame.loadTree(tree, treeFile);
2522   }
2523
2524   /**
2525    * bind structures in a viewer to any matching sequences in an alignFrame (use
2526    * sequenceIds to limit scope of search to specific sequences)
2527    * 
2528    * @param alFrame
2529    * @param viewer
2530    * @param sequenceIds
2531    * @return TODO: consider making an exception structure for indicating when
2532    *         binding fails public SequenceStructureBinding
2533    *         addStructureViewInstance( AlignFrame alFrame, Object viewer, String
2534    *         sequenceIds) {
2535    * 
2536    *         if (sequenceIds != null && sequenceIds.length() > 0) { return
2537    *         alFrame.addStructureViewInstance(viewer,
2538    *         separatorListToArray(sequenceIds)); } else { return
2539    *         alFrame.addStructureViewInstance(viewer, null); } // return null; }
2540    */
2541 }