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