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