8fe90f53f0c8b89e72ff2d99c4283a4e8582a782
[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
44 import java.applet.Applet;
45 import java.awt.Button;
46 import java.awt.Color;
47 import java.awt.Component;
48 import java.awt.EventQueue;
49 import java.awt.Font;
50 import java.awt.Frame;
51 import java.awt.Graphics;
52 import java.awt.event.ActionEvent;
53 import java.awt.event.WindowAdapter;
54 import java.awt.event.WindowEvent;
55 import java.io.BufferedReader;
56 import java.io.InputStreamReader;
57 import java.net.URL;
58 import java.util.Hashtable;
59 import java.util.StringTokenizer;
60 import java.util.Vector;
61
62 import netscape.javascript.JSObject;
63
64 /**
65  * Jalview Applet. Runs in Java 1.18 runtime
66  * 
67  * @author $author$
68  * @version $Revision: 1.92 $
69  */
70 public class JalviewLite extends Applet implements
71         StructureSelectionManagerProvider, JalviewLiteJsApi
72 {
73
74   public StructureSelectionManager getStructureSelectionManager()
75   {
76     return StructureSelectionManager.getStructureSelectionManager(this);
77   }
78
79   // /////////////////////////////////////////
80   // The following public methods maybe called
81   // externally, eg via javascript in HTML page
82   /*
83    * (non-Javadoc)
84    * 
85    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences()
86    */
87   public String getSelectedSequences()
88   {
89     return getSelectedSequencesFrom(getDefaultTargetFrame());
90   }
91
92   /*
93    * (non-Javadoc)
94    * 
95    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences(java.lang.String)
96    */
97   public String getSelectedSequences(String sep)
98   {
99     return getSelectedSequencesFrom(getDefaultTargetFrame(), sep);
100   }
101
102   /*
103    * (non-Javadoc)
104    * 
105    * @see
106    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
107    * .AlignFrame)
108    */
109   public String getSelectedSequencesFrom(AlignFrame alf)
110   {
111     return getSelectedSequencesFrom(alf, separator); // ""+0x00AC);
112   }
113
114   /*
115    * (non-Javadoc)
116    * 
117    * @see
118    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
119    * .AlignFrame, java.lang.String)
120    */
121   public String getSelectedSequencesFrom(AlignFrame alf, String sep)
122   {
123     StringBuffer result = new StringBuffer("");
124     if (sep == null || sep.length() == 0)
125     {
126       sep = separator; // "+0x00AC;
127     }
128     if (alf.viewport.getSelectionGroup() != null)
129     {
130       SequenceI[] seqs = alf.viewport.getSelectionGroup()
131               .getSequencesInOrder(alf.viewport.getAlignment());
132
133       for (int i = 0; i < seqs.length; i++)
134       {
135         result.append(seqs[i].getName());
136         result.append(sep);
137       }
138     }
139
140     return result.toString();
141   }
142
143   /*
144    * (non-Javadoc)
145    * 
146    * @see jalview.bin.JalviewLiteJsApi#highlight(java.lang.String,
147    * java.lang.String, java.lang.String)
148    */
149   public void highlight(String sequenceId, String position,
150           String alignedPosition)
151   {
152     highlightIn(getDefaultTargetFrame(), sequenceId, position,
153             alignedPosition);
154   }
155
156   /*
157    * (non-Javadoc)
158    * 
159    * @see jalview.bin.JalviewLiteJsApi#highlightIn(jalview.appletgui.AlignFrame,
160    * java.lang.String, java.lang.String, java.lang.String)
161    */
162   public void highlightIn(final AlignFrame alf, final String sequenceId,
163           final String position, final String alignedPosition)
164   {
165     // TODO: could try to highlight in all alignments if alf==null
166     jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
167             alf.viewport.getAlignment().getSequencesArray());
168     final SequenceI sq = matcher.findIdMatch(sequenceId);
169     if (sq != null)
170     {
171       int apos = -1;
172       try
173       {
174         apos = new Integer(position).intValue();
175         apos--;
176       } catch (NumberFormatException ex)
177       {
178         return;
179       }
180       final StructureSelectionManagerProvider me = this;
181       final int pos = apos;
182       // use vamsas listener to broadcast to all listeners in scope
183       if (alignedPosition != null
184               && (alignedPosition.trim().length() == 0 || alignedPosition
185                       .toLowerCase().indexOf("false") > -1))
186       {
187         java.awt.EventQueue.invokeLater(new Runnable()
188         {
189           @Override
190           public void run()
191           {
192             StructureSelectionManager.getStructureSelectionManager(me)
193                     .mouseOverVamsasSequence(sq, sq.findIndex(pos), null);
194           }
195         });
196       }
197       else
198       {
199         java.awt.EventQueue.invokeLater(new Runnable()
200         {
201           @Override
202           public void run()
203           {
204             StructureSelectionManager.getStructureSelectionManager(me)
205                     .mouseOverVamsasSequence(sq, pos, null);
206           }
207         });
208       }
209     }
210   }
211
212   /*
213    * (non-Javadoc)
214    * 
215    * @see jalview.bin.JalviewLiteJsApi#select(java.lang.String,
216    * java.lang.String)
217    */
218   public void select(String sequenceIds, String columns)
219   {
220     selectIn(getDefaultTargetFrame(), sequenceIds, columns, separator);
221   }
222
223   /*
224    * (non-Javadoc)
225    * 
226    * @see jalview.bin.JalviewLiteJsApi#select(java.lang.String,
227    * java.lang.String, java.lang.String)
228    */
229   public void select(String sequenceIds, String columns, String sep)
230   {
231     selectIn(getDefaultTargetFrame(), sequenceIds, columns, sep);
232   }
233
234   /*
235    * (non-Javadoc)
236    * 
237    * @see jalview.bin.JalviewLiteJsApi#selectIn(jalview.appletgui.AlignFrame,
238    * java.lang.String, java.lang.String)
239    */
240   public void selectIn(AlignFrame alf, String sequenceIds, String columns)
241   {
242     selectIn(alf, sequenceIds, columns, separator);
243   }
244
245   /*
246    * (non-Javadoc)
247    * 
248    * @see jalview.bin.JalviewLiteJsApi#selectIn(jalview.appletgui.AlignFrame,
249    * java.lang.String, java.lang.String, java.lang.String)
250    */
251   public void selectIn(final AlignFrame alf, String sequenceIds,
252           String columns, String sep)
253   {
254     if (sep == null || sep.length() == 0)
255     {
256       sep = separator;
257     }
258     else
259     {
260       if (debug)
261       {
262         System.err.println("Selecting region using separator string '"
263                 + separator + "'");
264       }
265     }
266     // deparse fields
267     String[] ids = separatorListToArray(sequenceIds, sep);
268     String[] cols = separatorListToArray(columns, sep);
269     final SequenceGroup sel = new SequenceGroup();
270     final ColumnSelection csel = new ColumnSelection();
271     AlignmentI al = alf.viewport.getAlignment();
272     jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
273             alf.viewport.getAlignment().getSequencesArray());
274     int start = 0, end = al.getWidth(), alw = al.getWidth();
275     boolean seqsfound = true;
276     if (ids != null && ids.length > 0)
277     {
278       seqsfound = false;
279       for (int i = 0; i < ids.length; i++)
280       {
281         if (ids[i].trim().length() == 0)
282         {
283           continue;
284         }
285         SequenceI sq = matcher.findIdMatch(ids[i]);
286         if (sq != null)
287         {
288           seqsfound = true;
289           sel.addSequence(sq, false);
290         }
291       }
292     }
293     boolean inseqpos = false;
294     if (cols != null && cols.length > 0)
295     {
296       boolean seset = false;
297       for (int i = 0; i < cols.length; i++)
298       {
299         String cl = cols[i].trim();
300         if (cl.length() == 0)
301         {
302           continue;
303         }
304         int p;
305         if ((p = cl.indexOf("-")) > -1)
306         {
307           int from = -1, to = -1;
308           try
309           {
310             from = new Integer(cl.substring(0, p)).intValue();
311             from--;
312           } catch (NumberFormatException ex)
313           {
314             System.err
315                     .println("ERROR: Couldn't parse first integer in range element column selection string '"
316                             + cl + "' - format is 'from-to'");
317             return;
318           }
319           try
320           {
321             to = new Integer(cl.substring(p + 1)).intValue();
322             to--;
323           } catch (NumberFormatException ex)
324           {
325             System.err
326                     .println("ERROR: Couldn't parse second integer in range element column selection string '"
327                             + cl + "' - format is 'from-to'");
328             return;
329           }
330           if (from >= 0 && to >= 0)
331           {
332             // valid range
333             if (from < to)
334             {
335               int t = to;
336               to = from;
337               to = t;
338             }
339             if (!seset)
340             {
341               start = from;
342               end = to;
343               seset = true;
344             }
345             else
346             {
347               // comment to prevent range extension
348               if (start > from)
349               {
350                 start = from;
351               }
352               if (end < to)
353               {
354                 end = to;
355               }
356             }
357             for (int r = from; r <= to; r++)
358             {
359               if (r >= 0 && r < alw)
360               {
361                 csel.addElement(r);
362               }
363             }
364             if (debug)
365             {
366               System.err.println("Range '" + cl + "' deparsed as [" + from
367                       + "," + to + "]");
368             }
369           }
370           else
371           {
372             System.err.println("ERROR: Invalid Range '" + cl
373                     + "' deparsed as [" + from + "," + to + "]");
374           }
375         }
376         else
377         {
378           int r = -1;
379           try
380           {
381             r = new Integer(cl).intValue();
382             r--;
383           } catch (NumberFormatException ex)
384           {
385             if (cl.toLowerCase().equals("sequence"))
386             {
387               // we are in the dataset sequence's coordinate frame.
388               inseqpos = true;
389             }
390             else
391             {
392               System.err
393                       .println("ERROR: Couldn't parse integer from point selection element of column selection string '"
394                               + cl + "'");
395               return;
396             }
397           }
398           if (r >= 0 && r <= alw)
399           {
400             if (!seset)
401             {
402               start = r;
403               end = r;
404               seset = true;
405             }
406             else
407             {
408               // comment to prevent range extension
409               if (start > r)
410               {
411                 start = r;
412               }
413               if (end < r)
414               {
415                 end = r;
416               }
417             }
418             csel.addElement(r);
419             if (debug)
420             {
421               System.err.println("Point selection '" + cl
422                       + "' deparsed as [" + r + "]");
423             }
424           }
425           else
426           {
427             System.err.println("ERROR: Invalid Point selection '" + cl
428                     + "' deparsed as [" + r + "]");
429           }
430         }
431       }
432     }
433     if (seqsfound)
434     {
435       // we only propagate the selection when it was the null selection, or the
436       // given sequences were found in the alignment.
437       if (inseqpos && sel.getSize() > 0)
438       {
439         // assume first sequence provides reference frame ?
440         SequenceI rs = sel.getSequenceAt(0);
441         start = rs.findIndex(start);
442         end = rs.findIndex(end);
443         if (csel != null)
444         {
445           Vector cs = csel.getSelected();
446           csel.clear();
447           for (int csi = 0, csiS = cs.size(); csi < csiS; csi++)
448           {
449             csel.addElement(rs.findIndex(((Integer) cs.elementAt(csi))
450                     .intValue()));
451           }
452         }
453       }
454       sel.setStartRes(start);
455       sel.setEndRes(end);
456       EventQueue.invokeLater(new Runnable()
457       {
458         @Override
459         public void run()
460         {
461           alf.select(sel, csel);
462         }
463       });
464     }
465   }
466
467   /*
468    * (non-Javadoc)
469    * 
470    * @see
471    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesAsAlignment(java.lang.
472    * String, java.lang.String)
473    */
474   public String getSelectedSequencesAsAlignment(String format, String suffix)
475   {
476     return getSelectedSequencesAsAlignmentFrom(getDefaultTargetFrame(),
477             format, suffix);
478   }
479
480   /*
481    * (non-Javadoc)
482    * 
483    * @see
484    * jalview.bin.JalviewLiteJsApi#getSelectedSequencesAsAlignmentFrom(jalview
485    * .appletgui.AlignFrame, java.lang.String, java.lang.String)
486    */
487   public String getSelectedSequencesAsAlignmentFrom(AlignFrame alf,
488           String format, String suffix)
489   {
490     try
491     {
492       boolean seqlimits = suffix.equalsIgnoreCase("true");
493       if (alf.viewport.getSelectionGroup() != null)
494       {
495         // JBPNote: getSelectionAsNewSequence behaviour has changed - this
496         // method now returns a full copy of sequence data
497         // TODO consider using getSequenceSelection instead here
498         String reply = new AppletFormatAdapter().formatSequences(format,
499                 new Alignment(alf.viewport.getSelectionAsNewSequence()),
500                 seqlimits);
501         return reply;
502       }
503     } catch (Exception ex)
504     {
505       ex.printStackTrace();
506       return "Error retrieving alignment in " + format + " format. ";
507     }
508     return "";
509   }
510
511   /*
512    * (non-Javadoc)
513    * 
514    * @see jalview.bin.JalviewLiteJsApi#getAlignmentOrder()
515    */
516   public String getAlignmentOrder()
517   {
518     return getAlignmentOrderFrom(getDefaultTargetFrame());
519   }
520
521   /*
522    * (non-Javadoc)
523    * 
524    * @see
525    * jalview.bin.JalviewLiteJsApi#getAlignmentOrderFrom(jalview.appletgui.AlignFrame
526    * )
527    */
528   public String getAlignmentOrderFrom(AlignFrame alf)
529   {
530     return getAlignmentOrderFrom(alf, separator);
531   }
532
533   /*
534    * (non-Javadoc)
535    * 
536    * @see
537    * jalview.bin.JalviewLiteJsApi#getAlignmentOrderFrom(jalview.appletgui.AlignFrame
538    * , java.lang.String)
539    */
540   public String getAlignmentOrderFrom(AlignFrame alf, String sep)
541   {
542     AlignmentI alorder = alf.getAlignViewport().getAlignment();
543     String[] order = new String[alorder.getHeight()];
544     for (int i = 0; i < order.length; i++)
545     {
546       order[i] = alorder.getSequenceAt(i).getName();
547     }
548     return arrayToSeparatorList(order);
549   }
550
551   /*
552    * (non-Javadoc)
553    * 
554    * @see jalview.bin.JalviewLiteJsApi#orderBy(java.lang.String,
555    * java.lang.String)
556    */
557   public String orderBy(String order, String undoName)
558   {
559     return orderBy(order, undoName, separator);
560   }
561
562   /*
563    * (non-Javadoc)
564    * 
565    * @see jalview.bin.JalviewLiteJsApi#orderBy(java.lang.String,
566    * java.lang.String, java.lang.String)
567    */
568   public String orderBy(String order, String undoName, String sep)
569   {
570     return orderAlignmentBy(getDefaultTargetFrame(), order, undoName, sep);
571   }
572
573   /*
574    * (non-Javadoc)
575    * 
576    * @see
577    * jalview.bin.JalviewLiteJsApi#orderAlignmentBy(jalview.appletgui.AlignFrame,
578    * java.lang.String, java.lang.String, java.lang.String)
579    */
580   public String orderAlignmentBy(AlignFrame alf, String order,
581           String undoName, String sep)
582   {
583     String[] ids = separatorListToArray(order, sep);
584     SequenceI[] sqs = null;
585     if (ids != null && ids.length > 0)
586     {
587       jalview.analysis.SequenceIdMatcher matcher = new jalview.analysis.SequenceIdMatcher(
588               alf.viewport.getAlignment().getSequencesArray());
589       int s = 0;
590       sqs = new SequenceI[ids.length];
591       for (int i = 0; i < ids.length; i++)
592       {
593         if (ids[i].trim().length() == 0)
594         {
595           continue;
596         }
597         SequenceI sq = matcher.findIdMatch(ids[i]);
598         if (sq != null)
599         {
600           sqs[s++] = sq;
601         }
602       }
603       if (s > 0)
604       {
605         SequenceI[] sqq = new SequenceI[s];
606         System.arraycopy(sqs, 0, sqq, 0, s);
607         sqs = sqq;
608       }
609       else
610       {
611         sqs = null;
612       }
613     }
614     if (sqs == null)
615     {
616       return "";
617     }
618     ;
619     final AlignmentOrder aorder = new AlignmentOrder(sqs);
620
621     if (undoName != null && undoName.trim().length() == 0)
622     {
623       undoName = null;
624     }
625     final String _undoName = undoName;
626     // TODO: deal with synchronization here: cannot raise any events until after
627     // this has returned.
628     return alf.sortBy(aorder, _undoName) ? "true" : "";
629   }
630
631   /*
632    * (non-Javadoc)
633    * 
634    * @see jalview.bin.JalviewLiteJsApi#getAlignment(java.lang.String)
635    */
636   public String getAlignment(String format)
637   {
638     return getAlignmentFrom(getDefaultTargetFrame(), format, "true");
639   }
640
641   /*
642    * (non-Javadoc)
643    * 
644    * @see
645    * jalview.bin.JalviewLiteJsApi#getAlignmentFrom(jalview.appletgui.AlignFrame,
646    * java.lang.String)
647    */
648   public String getAlignmentFrom(AlignFrame alf, String format)
649   {
650     return getAlignmentFrom(alf, format, "true");
651   }
652
653   /*
654    * (non-Javadoc)
655    * 
656    * @see jalview.bin.JalviewLiteJsApi#getAlignment(java.lang.String,
657    * java.lang.String)
658    */
659   public String getAlignment(String format, String suffix)
660   {
661     return getAlignmentFrom(getDefaultTargetFrame(), format, suffix);
662   }
663
664   /*
665    * (non-Javadoc)
666    * 
667    * @see
668    * jalview.bin.JalviewLiteJsApi#getAlignmentFrom(jalview.appletgui.AlignFrame,
669    * java.lang.String, java.lang.String)
670    */
671   public String getAlignmentFrom(AlignFrame alf, String format,
672           String suffix)
673   {
674     try
675     {
676       boolean seqlimits = suffix.equalsIgnoreCase("true");
677
678       String reply = new AppletFormatAdapter().formatSequences(format,
679               alf.viewport.getAlignment(), seqlimits);
680       return reply;
681     } catch (Exception ex)
682     {
683       ex.printStackTrace();
684       return "Error retrieving alignment in " + format + " format. ";
685     }
686   }
687
688   /*
689    * (non-Javadoc)
690    * 
691    * @see jalview.bin.JalviewLiteJsApi#loadAnnotation(java.lang.String)
692    */
693   public void loadAnnotation(String annotation)
694   {
695     loadAnnotationFrom(getDefaultTargetFrame(), annotation);
696   }
697
698   /*
699    * (non-Javadoc)
700    * 
701    * @see
702    * jalview.bin.JalviewLiteJsApi#loadAnnotationFrom(jalview.appletgui.AlignFrame
703    * , java.lang.String)
704    */
705   public void loadAnnotationFrom(AlignFrame alf, String annotation)
706   {
707     if (new AnnotationFile().readAnnotationFile(alf.getAlignViewport()
708             .getAlignment(), annotation, AppletFormatAdapter.PASTE))
709     {
710       alf.alignPanel.fontChanged();
711       alf.alignPanel.setScrollValues(0, 0);
712     }
713     else
714     {
715       alf.parseFeaturesFile(annotation, AppletFormatAdapter.PASTE);
716     }
717   }
718
719   /*
720    * (non-Javadoc)
721    * 
722    * @see jalview.bin.JalviewLiteJsApi#loadAnnotation(java.lang.String)
723    */
724   public void loadFeatures(String features, boolean autoenabledisplay)
725   {
726     loadFeaturesFrom(getDefaultTargetFrame(), features, autoenabledisplay);
727   }
728
729   /*
730    * (non-Javadoc)
731    * 
732    * @see
733    * jalview.bin.JalviewLiteJsApi#loadAnnotationFrom(jalview.appletgui.AlignFrame
734    * , java.lang.String)
735    */
736   public boolean loadFeaturesFrom(AlignFrame alf, String features,
737           boolean autoenabledisplay)
738   {
739     return alf.parseFeaturesFile(features, AppletFormatAdapter.PASTE,
740             autoenabledisplay);
741   }
742
743   /*
744    * (non-Javadoc)
745    * 
746    * @see jalview.bin.JalviewLiteJsApi#getFeatures(java.lang.String)
747    */
748   public String getFeatures(String format)
749   {
750     return getFeaturesFrom(getDefaultTargetFrame(), format);
751   }
752
753   /*
754    * (non-Javadoc)
755    * 
756    * @see
757    * jalview.bin.JalviewLiteJsApi#getFeaturesFrom(jalview.appletgui.AlignFrame,
758    * java.lang.String)
759    */
760   public String getFeaturesFrom(AlignFrame alf, String format)
761   {
762     return alf.outputFeatures(false, format);
763   }
764
765   /*
766    * (non-Javadoc)
767    * 
768    * @see jalview.bin.JalviewLiteJsApi#getAnnotation()
769    */
770   public String getAnnotation()
771   {
772     return getAnnotationFrom(getDefaultTargetFrame());
773   }
774
775   /*
776    * (non-Javadoc)
777    * 
778    * @see
779    * jalview.bin.JalviewLiteJsApi#getAnnotationFrom(jalview.appletgui.AlignFrame
780    * )
781    */
782   public String getAnnotationFrom(AlignFrame alf)
783   {
784     return alf.outputAnnotations(false);
785   }
786
787   /*
788    * (non-Javadoc)
789    * 
790    * @see jalview.bin.JalviewLiteJsApi#newView()
791    */
792   public AlignFrame newView()
793   {
794     return newViewFrom(getDefaultTargetFrame());
795   }
796
797   /*
798    * (non-Javadoc)
799    * 
800    * @see jalview.bin.JalviewLiteJsApi#newView(java.lang.String)
801    */
802   public AlignFrame newView(String name)
803   {
804     return newViewFrom(getDefaultTargetFrame(), name);
805   }
806
807   /*
808    * (non-Javadoc)
809    * 
810    * @see jalview.bin.JalviewLiteJsApi#newViewFrom(jalview.appletgui.AlignFrame)
811    */
812   public AlignFrame newViewFrom(AlignFrame alf)
813   {
814     return alf.newView(null);
815   }
816
817   /*
818    * (non-Javadoc)
819    * 
820    * @see jalview.bin.JalviewLiteJsApi#newViewFrom(jalview.appletgui.AlignFrame,
821    * java.lang.String)
822    */
823   public AlignFrame newViewFrom(AlignFrame alf, String name)
824   {
825     return alf.newView(name);
826   }
827
828   /*
829    * (non-Javadoc)
830    * 
831    * @see jalview.bin.JalviewLiteJsApi#loadAlignment(java.lang.String,
832    * java.lang.String)
833    */
834   public AlignFrame loadAlignment(String text, String title)
835   {
836     Alignment al = null;
837
838     String format = new IdentifyFile().Identify(text,
839             AppletFormatAdapter.PASTE);
840     try
841     {
842       al = new AppletFormatAdapter().readFile(text,
843               AppletFormatAdapter.PASTE, format);
844       if (al.getHeight() > 0)
845       {
846         return new AlignFrame(al, this, title, false);
847       }
848     } catch (java.io.IOException ex)
849     {
850       ex.printStackTrace();
851     }
852     return null;
853   }
854
855   /*
856    * (non-Javadoc)
857    * 
858    * @see jalview.bin.JalviewLiteJsApi#setMouseoverListener(java.lang.String)
859    */
860   public void setMouseoverListener(String listener)
861   {
862     setMouseoverListener(currentAlignFrame, listener);
863   }
864
865   private Vector<jalview.javascript.JSFunctionExec> javascriptListeners = new Vector<jalview.javascript.JSFunctionExec>();
866
867   /*
868    * (non-Javadoc)
869    * 
870    * @see
871    * jalview.bin.JalviewLiteJsApi#setMouseoverListener(jalview.appletgui.AlignFrame
872    * , java.lang.String)
873    */
874   public void setMouseoverListener(AlignFrame af, String listener)
875   {
876     if (listener != null)
877     {
878       listener = listener.trim();
879       if (listener.length() == 0)
880       {
881         System.err
882                 .println("jalview Javascript error: Ignoring empty function for mouseover listener.");
883         return;
884       }
885     }
886     jalview.javascript.MouseOverListener mol = new jalview.javascript.MouseOverListener(
887             this, af, listener);
888     javascriptListeners.addElement(mol);
889     StructureSelectionManager.getStructureSelectionManager(this)
890             .addStructureViewerListener(mol);
891     if (debug)
892     {
893       System.err.println("Added a mouseover listener for "
894               + ((af == null) ? "All frames" : "Just views for "
895                       + af.getAlignViewport().getSequenceSetId()));
896       System.err.println("There are now " + javascriptListeners.size()
897               + " listeners in total.");
898     }
899   }
900
901   /*
902    * (non-Javadoc)
903    * 
904    * @see jalview.bin.JalviewLiteJsApi#setSelectionListener(java.lang.String)
905    */
906   public void setSelectionListener(String listener)
907   {
908     setSelectionListener(null, listener);
909   }
910
911   /*
912    * (non-Javadoc)
913    * 
914    * @see
915    * jalview.bin.JalviewLiteJsApi#setSelectionListener(jalview.appletgui.AlignFrame
916    * , java.lang.String)
917    */
918   public void setSelectionListener(AlignFrame af, String listener)
919   {
920     if (listener != null)
921     {
922       listener = listener.trim();
923       if (listener.length() == 0)
924       {
925         System.err
926                 .println("jalview Javascript error: Ignoring empty function for selection listener.");
927         return;
928       }
929     }
930     jalview.javascript.JsSelectionSender mol = new jalview.javascript.JsSelectionSender(
931             this, af, listener);
932     javascriptListeners.addElement(mol);
933     StructureSelectionManager.getStructureSelectionManager(this)
934             .addSelectionListener(mol);
935     if (debug)
936     {
937       System.err.println("Added a selection listener for "
938               + ((af == null) ? "All frames" : "Just views for "
939                       + af.getAlignViewport().getSequenceSetId()));
940       System.err.println("There are now " + javascriptListeners.size()
941               + " listeners in total.");
942     }
943   }
944
945   /*
946    * (non-Javadoc)
947    * 
948    * @see jalview.bin.JalviewLiteJsApi#setStructureListener(java.lang.String,
949    * java.lang.String)
950    */
951   public void setStructureListener(String listener, String modelSet)
952   {
953     if (listener != null)
954     {
955       listener = listener.trim();
956       if (listener.length() == 0)
957       {
958         System.err
959                 .println("jalview Javascript error: Ignoring empty function for selection listener.");
960         return;
961       }
962     }
963     jalview.javascript.MouseOverStructureListener mol = new jalview.javascript.MouseOverStructureListener(
964             this, listener, separatorListToArray(modelSet));
965     javascriptListeners.addElement(mol);
966     StructureSelectionManager.getStructureSelectionManager(this)
967             .addStructureViewerListener(mol);
968     if (debug)
969     {
970       System.err.println("Added a javascript structure viewer listener '"
971               + listener + "'");
972       System.err.println("There are now " + javascriptListeners.size()
973               + " listeners in total.");
974     }
975   }
976
977   /*
978    * (non-Javadoc)
979    * 
980    * @see
981    * jalview.bin.JalviewLiteJsApi#removeJavascriptListener(jalview.appletgui
982    * .AlignFrame, java.lang.String)
983    */
984   public void removeJavascriptListener(AlignFrame af, String listener)
985   {
986     if (listener != null)
987     {
988       listener = listener.trim();
989       if (listener.length() == 0)
990       {
991         listener = null;
992       }
993     }
994     boolean rprt = false;
995     for (int ms = 0, msSize = javascriptListeners.size(); ms < msSize;)
996     {
997       Object lstn = javascriptListeners.elementAt(ms);
998       JsCallBack lstner = (JsCallBack) lstn;
999       if ((af == null || lstner.getAlignFrame() == af)
1000               && (listener == null || lstner.getListenerFunction().equals(
1001                       listener)))
1002       {
1003         javascriptListeners.removeElement(lstner);
1004         msSize--;
1005         if (lstner instanceof SelectionListener)
1006         {
1007           StructureSelectionManager.getStructureSelectionManager(this)
1008                   .removeSelectionListener((SelectionListener) lstner);
1009         }
1010         else
1011         {
1012           StructureSelectionManager.getStructureSelectionManager(this)
1013                   .removeStructureViewerListener(lstner, null);
1014         }
1015         rprt = debug;
1016         if (debug)
1017         {
1018           System.err.println("Removed listener '" + listener + "'");
1019         }
1020       }
1021       else
1022       {
1023         ms++;
1024       }
1025     }
1026     if (rprt)
1027     {
1028       System.err.println("There are now " + javascriptListeners.size()
1029               + " listeners in total.");
1030     }
1031   }
1032
1033   public void stop()
1034   {
1035     System.err.println("Applet " + getName() + " stop().");
1036     tidyUp();
1037   }
1038
1039   public void destroy()
1040   {
1041     System.err.println("Applet " + getName() + " destroy().");
1042     tidyUp();
1043   }
1044
1045   private void tidyUp()
1046   {
1047     removeAll();
1048     if (currentAlignFrame != null && currentAlignFrame.viewport != null
1049             && currentAlignFrame.viewport.applet != null)
1050     {
1051       AlignViewport av = currentAlignFrame.viewport;
1052       currentAlignFrame.closeMenuItem_actionPerformed();
1053       av.applet = null;
1054       currentAlignFrame = null;
1055     }
1056     if (javascriptListeners != null)
1057     {
1058       while (javascriptListeners.size() > 0)
1059       {
1060         jalview.javascript.JSFunctionExec mol = javascriptListeners
1061                 .elementAt(0);
1062         javascriptListeners.removeElement(mol);
1063         if (mol instanceof SelectionListener)
1064         {
1065           StructureSelectionManager.getStructureSelectionManager(this)
1066                   .removeSelectionListener((SelectionListener) mol);
1067         }
1068         else
1069         {
1070           StructureSelectionManager.getStructureSelectionManager(this)
1071                   .removeStructureViewerListener(mol, null);
1072         }
1073         mol.jvlite = null;
1074       }
1075     }
1076     if (jsFunctionExec != null)
1077     {
1078       jsFunctionExec.stopQueue();
1079       jsFunctionExec.jvlite = null;
1080     }
1081     initialAlignFrame = null;
1082     jsFunctionExec = null;
1083     javascriptListeners = null;
1084     StructureSelectionManager.release(this);
1085   }
1086
1087   private jalview.javascript.JSFunctionExec jsFunctionExec;
1088
1089   /*
1090    * (non-Javadoc)
1091    * 
1092    * @see jalview.bin.JalviewLiteJsApi#mouseOverStructure(java.lang.String,
1093    * java.lang.String, java.lang.String)
1094    */
1095   public void mouseOverStructure(final String pdbResNum,
1096           final String chain, final String pdbfile)
1097   {
1098     final StructureSelectionManagerProvider me = this;
1099     java.awt.EventQueue.invokeLater(new Runnable()
1100     {
1101       @Override
1102       public void run()
1103       {
1104         try
1105         {
1106           StructureSelectionManager.getStructureSelectionManager(me)
1107                   .mouseOverStructure(new Integer(pdbResNum).intValue(),
1108                           chain, pdbfile);
1109           if (debug)
1110           {
1111             System.err.println("mouseOver for '" + pdbResNum
1112                     + "' in chain '" + chain + "' in structure '" + pdbfile
1113                     + "'");
1114           }
1115         } catch (NumberFormatException e)
1116         {
1117           System.err.println("Ignoring invalid residue number string '"
1118                   + pdbResNum + "'");
1119         }
1120
1121       }
1122     });
1123   }
1124
1125   /*
1126    * (non-Javadoc)
1127    * 
1128    * @see
1129    * jalview.bin.JalviewLiteJsApi#scrollViewToIn(jalview.appletgui.AlignFrame,
1130    * java.lang.String, java.lang.String)
1131    */
1132   public void scrollViewToIn(final AlignFrame alf, final String topRow,
1133           final String leftHandColumn)
1134   {
1135     java.awt.EventQueue.invokeLater(new Runnable()
1136     {
1137       @Override
1138       public void run()
1139       {
1140         try
1141         {
1142           alf.scrollTo(new Integer(topRow).intValue(), new Integer(
1143                   leftHandColumn).intValue());
1144
1145         } catch (Exception ex)
1146         {
1147           System.err.println("Couldn't parse integer arguments (topRow='"
1148                   + topRow + "' and leftHandColumn='" + leftHandColumn
1149                   + "')");
1150           ex.printStackTrace();
1151         }
1152       }
1153     });
1154   }
1155
1156   /*
1157    * (non-Javadoc)
1158    * 
1159    * @see
1160    * jalview.javascript.JalviewLiteJsApi#scrollViewToRowIn(jalview.appletgui
1161    * .AlignFrame, java.lang.String)
1162    */
1163   @Override
1164   public void scrollViewToRowIn(final AlignFrame alf, final String topRow)
1165   {
1166
1167     java.awt.EventQueue.invokeLater(new Runnable()
1168     {
1169       @Override
1170       public void run()
1171       {
1172         try
1173         {
1174           alf.scrollToRow(new Integer(topRow).intValue());
1175
1176         } catch (Exception ex)
1177         {
1178           System.err.println("Couldn't parse integer arguments (topRow='"
1179                   + topRow + "')");
1180           ex.printStackTrace();
1181         }
1182
1183       }
1184     });
1185   }
1186
1187   /*
1188    * (non-Javadoc)
1189    * 
1190    * @see
1191    * jalview.javascript.JalviewLiteJsApi#scrollViewToColumnIn(jalview.appletgui
1192    * .AlignFrame, java.lang.String)
1193    */
1194   @Override
1195   public void scrollViewToColumnIn(final AlignFrame alf,
1196           final String leftHandColumn)
1197   {
1198     java.awt.EventQueue.invokeLater(new Runnable()
1199     {
1200
1201       @Override
1202       public void run()
1203       {
1204         try
1205         {
1206           alf.scrollToColumn(new Integer(leftHandColumn).intValue());
1207
1208         } catch (Exception ex)
1209         {
1210           System.err
1211                   .println("Couldn't parse integer arguments (leftHandColumn='"
1212                           + leftHandColumn + "')");
1213           ex.printStackTrace();
1214         }
1215       }
1216     });
1217
1218   }
1219
1220   // //////////////////////////////////////////////
1221   // //////////////////////////////////////////////
1222
1223   public static int lastFrameX = 200;
1224
1225   public static int lastFrameY = 200;
1226
1227   boolean fileFound = true;
1228
1229   String file = "No file";
1230
1231   Button launcher = new Button("Start Jalview");
1232
1233   /**
1234    * The currentAlignFrame is static, it will change if and when the user
1235    * selects a new window. Note that it will *never* point back to the embedded
1236    * AlignFrame if the applet is started as embedded on the page and then
1237    * afterwards a new view is created.
1238    */
1239   public AlignFrame currentAlignFrame = null;
1240
1241   /**
1242    * This is the first frame to be displayed, and does not change. API calls
1243    * will default to this instance if currentAlignFrame is null.
1244    */
1245   AlignFrame initialAlignFrame = null;
1246
1247   boolean embedded = false;
1248
1249   private boolean checkForJmol = true;
1250
1251   private boolean checkedForJmol = false; // ensure we don't check for jmol
1252
1253   // every time the app is re-inited
1254
1255   public boolean jmolAvailable = false;
1256
1257   private boolean alignPdbStructures = false;
1258
1259   /**
1260    * use an external structure viewer exclusively (no jmols or MCViews will be
1261    * opened by JalviewLite itself)
1262    */
1263   public boolean useXtrnalSviewer = false;
1264
1265   public static boolean debug = false;
1266
1267   static String builddate = null, version = null;
1268
1269   private static void initBuildDetails()
1270   {
1271     if (builddate == null)
1272     {
1273       builddate = "unknown";
1274       version = "test";
1275       java.net.URL url = JalviewLite.class
1276               .getResource("/.build_properties");
1277       if (url != null)
1278       {
1279         try
1280         {
1281           BufferedReader reader = new BufferedReader(new InputStreamReader(
1282                   url.openStream()));
1283           String line;
1284           while ((line = reader.readLine()) != null)
1285           {
1286             if (line.indexOf("VERSION") > -1)
1287             {
1288               version = line.substring(line.indexOf("=") + 1);
1289             }
1290             if (line.indexOf("BUILD_DATE") > -1)
1291             {
1292               builddate = line.substring(line.indexOf("=") + 1);
1293             }
1294           }
1295         } catch (Exception ex)
1296         {
1297           ex.printStackTrace();
1298         }
1299       }
1300     }
1301   }
1302
1303   public static String getBuildDate()
1304   {
1305     initBuildDetails();
1306     return builddate;
1307   }
1308
1309   public static String getVersion()
1310   {
1311     initBuildDetails();
1312     return version;
1313   }
1314
1315   // public JSObject scriptObject = null;
1316
1317   /**
1318    * init method for Jalview Applet
1319    */
1320   public void init()
1321   {
1322     // remove any handlers that might be hanging around from an earlier instance
1323     try
1324     {
1325       if (debug)
1326       {
1327         System.err.println("Applet context is '"
1328                 + getAppletContext().getClass().toString() + "'");
1329       }
1330       JSObject scriptObject = JSObject.getWindow(this);
1331       if (debug && scriptObject != null)
1332       {
1333         System.err.println("Applet has Javascript callback support.");
1334       }
1335
1336     } catch (Exception ex)
1337     {
1338       System.err
1339               .println("Warning: No JalviewLite javascript callbacks available.");
1340       if (debug)
1341       {
1342         ex.printStackTrace();
1343       }
1344     }
1345     /**
1346      * turn on extra applet debugging
1347      */
1348     String dbg = getParameter("debug");
1349     if (dbg != null)
1350     {
1351       debug = dbg.toLowerCase().equals("true");
1352     }
1353     if (debug)
1354     {
1355
1356       System.err.println("JalviewLite Version " + getVersion());
1357       System.err.println("Build Date : " + getBuildDate());
1358
1359     }
1360     String externalsviewer = getParameter("externalstructureviewer");
1361     if (externalsviewer != null)
1362     {
1363       useXtrnalSviewer = externalsviewer.trim().toLowerCase()
1364               .equals("true");
1365     }
1366     /**
1367      * if true disable the check for jmol
1368      */
1369     String chkforJmol = getParameter("nojmol");
1370     if (chkforJmol != null)
1371     {
1372       checkForJmol = !chkforJmol.equals("true");
1373     }
1374     /**
1375      * get the separator parameter if present
1376      */
1377     String sep = getParameter("separator");
1378     if (sep != null)
1379     {
1380       if (sep.length() > 0)
1381       {
1382         separator = sep;
1383         if (debug)
1384         {
1385           System.err.println("Separator set to '" + separator + "'");
1386         }
1387       }
1388       else
1389       {
1390         throw new Error(
1391                 "Invalid separator parameter - must be non-zero length");
1392       }
1393     }
1394     int r = 255;
1395     int g = 255;
1396     int b = 255;
1397     String param = getParameter("RGB");
1398
1399     if (param != null)
1400     {
1401       try
1402       {
1403         r = Integer.parseInt(param.substring(0, 2), 16);
1404         g = Integer.parseInt(param.substring(2, 4), 16);
1405         b = Integer.parseInt(param.substring(4, 6), 16);
1406       } catch (Exception ex)
1407       {
1408         r = 255;
1409         g = 255;
1410         b = 255;
1411       }
1412     }
1413     param = getParameter("label");
1414     if (param != null)
1415     {
1416       launcher.setLabel(param);
1417     }
1418
1419     setBackground(new Color(r, g, b));
1420
1421     file = getParameter("file");
1422
1423     if (file == null)
1424     {
1425       // Maybe the sequences are added as parameters
1426       StringBuffer data = new StringBuffer("PASTE");
1427       int i = 1;
1428       while ((file = getParameter("sequence" + i)) != null)
1429       {
1430         data.append(file.toString() + "\n");
1431         i++;
1432       }
1433       if (data.length() > 5)
1434       {
1435         file = data.toString();
1436       }
1437     }
1438
1439     final JalviewLite jvapplet = this;
1440     if (getParameter("embedded") != null
1441             && getParameter("embedded").equalsIgnoreCase("true"))
1442     {
1443       // Launch as embedded applet in page
1444       embedded = true;
1445       LoadingThread loader = new LoadingThread(file, jvapplet);
1446       loader.start();
1447     }
1448     else if (file != null)
1449     {
1450       if (getParameter("showbutton") == null
1451               || !getParameter("showbutton").equalsIgnoreCase("false"))
1452       {
1453         // Add the JalviewLite 'Button' to the page
1454         add(launcher);
1455         launcher.addActionListener(new java.awt.event.ActionListener()
1456         {
1457           public void actionPerformed(ActionEvent e)
1458           {
1459             LoadingThread loader = new LoadingThread(file, jvapplet);
1460             loader.start();
1461           }
1462         });
1463       }
1464       else
1465       {
1466         // Open jalviewLite immediately.
1467         LoadingThread loader = new LoadingThread(file, jvapplet);
1468         loader.start();
1469       }
1470     }
1471     else
1472     {
1473       // jalview initialisation with no alignment. loadAlignment() method can
1474       // still be called to open new alignments.
1475       file = "NO FILE";
1476       fileFound = false;
1477       callInitCallback();
1478     }
1479   }
1480
1481   private void callInitCallback()
1482   {
1483     String initjscallback = getParameter("oninit");
1484     if (initjscallback == null)
1485     {
1486       return;
1487     }
1488     initjscallback = initjscallback.trim();
1489     if (initjscallback.length() > 0)
1490     {
1491       JSObject scriptObject = null;
1492       try
1493       {
1494         scriptObject = JSObject.getWindow(this);
1495       } catch (Exception ex)
1496       {
1497       }
1498       ;
1499       if (scriptObject != null)
1500       {
1501         try
1502         {
1503           // do onInit with the JS executor thread
1504           new JSFunctionExec(this).executeJavascriptFunction(true,
1505                   initjscallback, null, "Calling oninit callback '"
1506                           + initjscallback + "'.");
1507         } catch (Exception e)
1508         {
1509           System.err.println("Exception when executing _oninit callback '"
1510                   + initjscallback + "'.");
1511           e.printStackTrace();
1512         }
1513       }
1514       else
1515       {
1516         System.err.println("Not executing _oninit callback '"
1517                 + initjscallback + "' - no scripting allowed.");
1518       }
1519     }
1520   }
1521
1522   /**
1523    * Initialises and displays a new java.awt.Frame
1524    * 
1525    * @param frame
1526    *          java.awt.Frame to be displayed
1527    * @param title
1528    *          title of new frame
1529    * @param width
1530    *          width if new frame
1531    * @param height
1532    *          height of new frame
1533    */
1534   public static void addFrame(final Frame frame, String title, int width,
1535           int height)
1536   {
1537     frame.setLocation(lastFrameX, lastFrameY);
1538     lastFrameX += 40;
1539     lastFrameY += 40;
1540     frame.setSize(width, height);
1541     frame.setTitle(title);
1542     frame.addWindowListener(new WindowAdapter()
1543     {
1544       public void windowClosing(WindowEvent e)
1545       {
1546         if (frame instanceof AlignFrame)
1547         {
1548           AlignViewport vp = ((AlignFrame) frame).viewport;
1549           ((AlignFrame) frame).closeMenuItem_actionPerformed();
1550           if (vp.applet.currentAlignFrame == frame)
1551           {
1552             vp.applet.currentAlignFrame = null;
1553           }
1554           vp.applet = null;
1555           vp = null;
1556
1557         }
1558         lastFrameX -= 40;
1559         lastFrameY -= 40;
1560         if (frame instanceof EmbmenuFrame)
1561         {
1562           ((EmbmenuFrame) frame).destroyMenus();
1563         }
1564         frame.setMenuBar(null);
1565         frame.dispose();
1566       }
1567
1568       public void windowActivated(WindowEvent e)
1569       {
1570         if (frame instanceof AlignFrame)
1571         {
1572           ((AlignFrame) frame).viewport.applet.currentAlignFrame = (AlignFrame) frame;
1573           if (debug)
1574           {
1575             System.err.println("Activated window " + frame);
1576           }
1577         }
1578         // be good.
1579         super.windowActivated(e);
1580       }
1581       /*
1582        * Probably not necessary to do this - see TODO above. (non-Javadoc)
1583        * 
1584        * @see
1585        * java.awt.event.WindowAdapter#windowDeactivated(java.awt.event.WindowEvent
1586        * )
1587        * 
1588        * public void windowDeactivated(WindowEvent e) { if (currentAlignFrame ==
1589        * frame) { currentAlignFrame = null; if (debug) {
1590        * System.err.println("Deactivated window "+frame); } }
1591        * super.windowDeactivated(e); }
1592        */
1593     });
1594     frame.setVisible(true);
1595   }
1596
1597   /**
1598    * This paints the background surrounding the "Launch Jalview button" <br>
1599    * <br>
1600    * If file given in parameter not found, displays error message
1601    * 
1602    * @param g
1603    *          graphics context
1604    */
1605   public void paint(Graphics g)
1606   {
1607     if (!fileFound)
1608     {
1609       g.setColor(new Color(200, 200, 200));
1610       g.setColor(Color.cyan);
1611       g.fillRect(0, 0, getSize().width, getSize().height);
1612       g.setColor(Color.red);
1613       g.drawString("Jalview can't open file", 5, 15);
1614       g.drawString("\"" + file + "\"", 5, 30);
1615     }
1616     else if (embedded)
1617     {
1618       g.setColor(Color.black);
1619       g.setFont(new Font("Arial", Font.BOLD, 24));
1620       g.drawString("Jalview Applet", 50, getSize().height / 2 - 30);
1621       g.drawString("Loading Data...", 50, getSize().height / 2);
1622     }
1623   }
1624
1625   /**
1626    * get all components associated with the applet of the given type
1627    * 
1628    * @param class1
1629    * @return
1630    */
1631   public Vector getAppletWindow(Class class1)
1632   {
1633     Vector wnds = new Vector();
1634     Component[] cmp = getComponents();
1635     if (cmp != null)
1636     {
1637       for (int i = 0; i < cmp.length; i++)
1638       {
1639         if (class1.isAssignableFrom(cmp[i].getClass()))
1640         {
1641           wnds.addElement(cmp);
1642         }
1643       }
1644     }
1645     return wnds;
1646   }
1647
1648   class LoadJmolThread extends Thread
1649   {
1650     private boolean running = false;
1651
1652     public void run()
1653     {
1654       if (running || checkedForJmol)
1655       {
1656         return;
1657       }
1658       running = true;
1659       if (checkForJmol)
1660       {
1661         try
1662         {
1663           if (!System.getProperty("java.version").startsWith("1.1"))
1664           {
1665             Class.forName("org.jmol.adapter.smarter.SmarterJmolAdapter");
1666             jmolAvailable = true;
1667           }
1668           if (!jmolAvailable)
1669           {
1670             System.out
1671                     .println("Jmol not available - Using MCview for structures");
1672           }
1673         } catch (java.lang.ClassNotFoundException ex)
1674         {
1675         }
1676       }
1677       else
1678       {
1679         jmolAvailable = false;
1680         if (debug)
1681         {
1682           System.err
1683                   .println("Skipping Jmol check. Will use MCView (probably)");
1684         }
1685       }
1686       checkedForJmol = true;
1687       running = false;
1688     }
1689
1690     public boolean notFinished()
1691     {
1692       return running || !checkedForJmol;
1693     }
1694   }
1695
1696   class LoadingThread extends Thread
1697   {
1698     /**
1699      * State variable: File source
1700      */
1701     String file;
1702
1703     /**
1704      * State variable: protocol for access to file source
1705      */
1706     String protocol;
1707
1708     /**
1709      * State variable: format of file source
1710      */
1711     String format;
1712
1713     String _file;
1714
1715     JalviewLite applet;
1716
1717     private void dbgMsg(String msg)
1718     {
1719       if (applet.debug)
1720       {
1721         System.err.println(msg);
1722       }
1723     }
1724
1725     /**
1726      * update the protocol state variable for accessing the datasource located
1727      * by file.
1728      * 
1729      * @param file
1730      * @return possibly updated datasource string
1731      */
1732     public String setProtocolState(String file)
1733     {
1734       if (file.startsWith("PASTE"))
1735       {
1736         file = file.substring(5);
1737         protocol = AppletFormatAdapter.PASTE;
1738       }
1739       else if (inArchive(file))
1740       {
1741         protocol = AppletFormatAdapter.CLASSLOADER;
1742       }
1743       else
1744       {
1745         file = addProtocol(file);
1746         protocol = AppletFormatAdapter.URL;
1747       }
1748       dbgMsg("Protocol identified as '" + protocol + "'");
1749       return file;
1750     }
1751
1752     public LoadingThread(String _file, JalviewLite _applet)
1753     {
1754       this._file = _file;
1755       applet = _applet;
1756     }
1757
1758     public void run()
1759     {
1760       LoadJmolThread jmolchecker = new LoadJmolThread();
1761       jmolchecker.start();
1762       while (jmolchecker.notFinished())
1763       {
1764         // wait around until the Jmol check is complete.
1765         try
1766         {
1767           Thread.sleep(2);
1768         } catch (Exception e)
1769         {
1770         }
1771         ;
1772       }
1773       startLoading();
1774       // applet.callInitCallback();
1775     }
1776
1777     private void startLoading()
1778     {
1779       AlignFrame newAlignFrame;
1780       dbgMsg("Loading thread started with:\n>>file\n" + _file + ">>endfile");
1781       file = setProtocolState(_file);
1782
1783       format = new jalview.io.IdentifyFile().Identify(file, protocol);
1784       dbgMsg("File identified as '" + format + "'");
1785       dbgMsg("Loading started.");
1786       Alignment al = null;
1787       try
1788       {
1789         al = new AppletFormatAdapter().readFile(file, protocol, format);
1790       } catch (java.io.IOException ex)
1791       {
1792         dbgMsg("File load exception.");
1793         ex.printStackTrace();
1794         if (debug)
1795         {
1796           try
1797           {
1798             FileParse fp = new FileParse(file, protocol);
1799             String ln = null;
1800             dbgMsg(">>>Dumping contents of '" + file + "' " + "("
1801                     + protocol + ")");
1802             while ((ln = fp.nextLine()) != null)
1803             {
1804               dbgMsg(ln);
1805             }
1806             dbgMsg(">>>Dump finished.");
1807           } catch (Exception e)
1808           {
1809             System.err
1810                     .println("Exception when trying to dump the content of the file parameter.");
1811             e.printStackTrace();
1812           }
1813         }
1814       }
1815       if ((al != null) && (al.getHeight() > 0))
1816       {
1817         dbgMsg("Successfully loaded file.");
1818         newAlignFrame = new AlignFrame(al, applet, file, embedded);
1819         if (initialAlignFrame == null)
1820         {
1821           initialAlignFrame = newAlignFrame;
1822         }
1823         // update the focus.
1824         currentAlignFrame = newAlignFrame;
1825
1826         if (protocol == jalview.io.AppletFormatAdapter.PASTE)
1827         {
1828           newAlignFrame.setTitle("Sequences from "
1829                   + applet.getDocumentBase());
1830         }
1831
1832         newAlignFrame.statusBar.setText("Successfully loaded file " + 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 }