JAL-1432 updated copyright notices
[jalview.git] / src / jalview / bin / JalviewLite.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.bin;
20
21 import jalview.api.StructureSelectionManagerProvider;
22 import jalview.appletgui.AlignFrame;
23 import jalview.appletgui.AlignViewport;
24 import jalview.appletgui.EmbmenuFrame;
25 import jalview.appletgui.FeatureSettings;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.AlignmentOrder;
29 import jalview.datamodel.ColumnSelection;
30 import jalview.datamodel.PDBEntry;
31 import jalview.datamodel.Sequence;
32 import jalview.datamodel.SequenceGroup;
33 import jalview.datamodel.SequenceI;
34 import jalview.io.AnnotationFile;
35 import jalview.io.AppletFormatAdapter;
36 import jalview.io.FileParse;
37 import jalview.io.IdentifyFile;
38 import jalview.io.JnetAnnotationMaker;
39 import jalview.javascript.JSFunctionExec;
40 import jalview.javascript.JalviewLiteJsApi;
41 import jalview.javascript.JsCallBack;
42 import jalview.structure.SelectionListener;
43 import jalview.structure.StructureSelectionManager;
44
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("Jalview can't 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("Jalview Applet", 50, getSize().height / 2 - 30);
1622       g.drawString("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("Sequences from "
1830                   + applet.getDocumentBase());
1831         }
1832
1833         newAlignFrame.statusBar.setText("Successfully loaded file " + file);
1834
1835         String treeFile = applet.getParameter("tree");
1836         if (treeFile == null)
1837         {
1838           treeFile = applet.getParameter("treeFile");
1839         }
1840
1841         if (treeFile != null)
1842         {
1843           try
1844           {
1845             treeFile = setProtocolState(treeFile);
1846             /*
1847              * if (inArchive(treeFile)) { protocol =
1848              * AppletFormatAdapter.CLASSLOADER; } else { protocol =
1849              * AppletFormatAdapter.URL; treeFile = addProtocol(treeFile); }
1850              */
1851             jalview.io.NewickFile fin = new jalview.io.NewickFile(treeFile,
1852                     protocol);
1853
1854             fin.parse();
1855
1856             if (fin.getTree() != null)
1857             {
1858               newAlignFrame.loadTree(fin, treeFile);
1859               dbgMsg("Successfuly imported tree.");
1860             }
1861             else
1862             {
1863               dbgMsg("Tree parameter did not resolve to a valid tree.");
1864             }
1865           } catch (Exception ex)
1866           {
1867             ex.printStackTrace();
1868           }
1869         }
1870
1871         /*
1872          * Try to load T-Coffee score file
1873          */
1874         String sScoreFile = applet.getParameter("scoreFile");
1875         if (sScoreFile != null && !"".equals(sScoreFile))
1876         {
1877           try
1878           {
1879             if (debug)
1880             {
1881               System.err
1882                       .println("Attempting to load T-COFFEE score file from the scoreFile parameter");
1883             }
1884             if (!newAlignFrame.loadScoreFile(sScoreFile))
1885             {
1886               System.err
1887                       .println("Failed to parse T-COFFEE parameter as a valid score file ('"
1888                               + sScoreFile + "')");
1889             }
1890           } catch (Exception e)
1891           {
1892             System.err.printf("Cannot read score file: '%s'. Cause: %s \n",
1893                     sScoreFile, e.getMessage());
1894           }
1895         }
1896
1897         // ///////////////////////////
1898         // modify display of features
1899         // we do this before any features have been loaded, ensuring any hidden
1900         // groups are hidden when features first displayed
1901         //
1902         // hide specific groups
1903         //
1904         String param = applet.getParameter("hidefeaturegroups");
1905         if (param != null)
1906         {
1907           newAlignFrame.setFeatureGroupState(separatorListToArray(param),
1908                   false);
1909           // applet.setFeatureGroupStateOn(newAlignFrame, param, false);
1910         }
1911         // show specific groups
1912         param = applet.getParameter("showfeaturegroups");
1913         if (param != null)
1914         {
1915           newAlignFrame.setFeatureGroupState(separatorListToArray(param),
1916                   true);
1917           // applet.setFeatureGroupStateOn(newAlignFrame, param, true);
1918         }
1919         // and now load features
1920         param = applet.getParameter("features");
1921         if (param != null)
1922         {
1923           param = setProtocolState(param);
1924
1925           newAlignFrame.parseFeaturesFile(param, protocol);
1926         }
1927
1928         param = applet.getParameter("showFeatureSettings");
1929         if (param != null && param.equalsIgnoreCase("true"))
1930         {
1931           newAlignFrame.viewport.showSequenceFeatures(true);
1932           new FeatureSettings(newAlignFrame.alignPanel);
1933         }
1934
1935         param = applet.getParameter("annotations");
1936         if (param != null)
1937         {
1938           param = setProtocolState(param);
1939
1940           if (new AnnotationFile().readAnnotationFile(
1941                   newAlignFrame.viewport.getAlignment(), param, protocol))
1942           {
1943             newAlignFrame.alignPanel.fontChanged();
1944             newAlignFrame.alignPanel.setScrollValues(0, 0);
1945           }
1946           else
1947           {
1948             System.err
1949                     .println("Annotations were not added from annotation file '"
1950                             + param + "'");
1951           }
1952
1953         }
1954
1955         param = applet.getParameter("jnetfile");
1956         if (param != null)
1957         {
1958           try
1959           {
1960             param = setProtocolState(param);
1961             jalview.io.JPredFile predictions = new jalview.io.JPredFile(
1962                     param, protocol);
1963             JnetAnnotationMaker.add_annotation(predictions,
1964                     newAlignFrame.viewport.getAlignment(), 0, false); // false==do
1965             // not
1966             // add
1967             // sequence
1968             // profile
1969             // from
1970             // concise
1971             // output
1972             newAlignFrame.alignPanel.fontChanged();
1973             newAlignFrame.alignPanel.setScrollValues(0, 0);
1974           } catch (Exception ex)
1975           {
1976             ex.printStackTrace();
1977           }
1978         }
1979         /*
1980          * <param name="alignpdbfiles" value="false/true"/> Undocumented for 2.6
1981          * - related to JAL-434
1982          */
1983         applet.setAlignPdbStructures(getDefaultParameter("alignpdbfiles",
1984                 false));
1985         /*
1986          * <param name="PDBfile" value="1gaq.txt PDB|1GAQ|1GAQ|A PDB|1GAQ|1GAQ|B
1987          * PDB|1GAQ|1GAQ|C">
1988          * 
1989          * <param name="PDBfile2" value="1gaq.txt A=SEQA B=SEQB C=SEQB">
1990          * 
1991          * <param name="PDBfile3" value="1q0o Q45135_9MICO">
1992          */
1993
1994         int pdbFileCount = 0;
1995         // Accumulate pdbs here if they are heading for the same view (if
1996         // alignPdbStructures is true)
1997         Vector pdbs = new Vector();
1998         // create a lazy matcher if we're asked to
1999         jalview.analysis.SequenceIdMatcher matcher = (applet
2000                 .getDefaultParameter("relaxedidmatch", false)) ? new jalview.analysis.SequenceIdMatcher(
2001                 newAlignFrame.getAlignViewport().getAlignment()
2002                         .getSequencesArray()) : null;
2003
2004         do
2005         {
2006           if (pdbFileCount > 0)
2007           {
2008             param = applet.getParameter("PDBFILE" + pdbFileCount);
2009           }
2010           else
2011           {
2012             param = applet.getParameter("PDBFILE");
2013           }
2014
2015           if (param != null)
2016           {
2017             PDBEntry pdb = new PDBEntry();
2018
2019             String seqstring;
2020             SequenceI[] seqs = null;
2021             String[] chains = null;
2022
2023             StringTokenizer st = new StringTokenizer(param, " ");
2024
2025             if (st.countTokens() < 2)
2026             {
2027               String sequence = applet.getParameter("PDBSEQ");
2028               if (sequence != null)
2029                 seqs = new SequenceI[]
2030                 { matcher == null ? (Sequence) newAlignFrame
2031                         .getAlignViewport().getAlignment()
2032                         .findName(sequence) : matcher.findIdMatch(sequence) };
2033
2034             }
2035             else
2036             {
2037               param = st.nextToken();
2038               Vector tmp = new Vector();
2039               Vector tmp2 = new Vector();
2040
2041               while (st.hasMoreTokens())
2042               {
2043                 seqstring = st.nextToken();
2044                 StringTokenizer st2 = new StringTokenizer(seqstring, "=");
2045                 if (st2.countTokens() > 1)
2046                 {
2047                   // This is the chain
2048                   tmp2.addElement(st2.nextToken());
2049                   seqstring = st2.nextToken();
2050                 }
2051                 tmp.addElement(matcher == null ? (Sequence) newAlignFrame
2052                         .getAlignViewport().getAlignment()
2053                         .findName(seqstring) : matcher
2054                         .findIdMatch(seqstring));
2055               }
2056
2057               seqs = new SequenceI[tmp.size()];
2058               tmp.copyInto(seqs);
2059               if (tmp2.size() == tmp.size())
2060               {
2061                 chains = new String[tmp2.size()];
2062                 tmp2.copyInto(chains);
2063               }
2064             }
2065             param = setProtocolState(param);
2066
2067             if (// !jmolAvailable
2068             // &&
2069             protocol == AppletFormatAdapter.CLASSLOADER
2070                     && !useXtrnalSviewer)
2071             {
2072               // Re: JAL-357 : the bug isn't a problem if we are using an
2073               // external viewer!
2074               // TODO: verify this Re:
2075               // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
2076               // This exception preserves the current behaviour where, even if
2077               // the local pdb file was identified in the class loader
2078               protocol = AppletFormatAdapter.URL; // this is probably NOT
2079               // CORRECT!
2080               param = addProtocol(param); //
2081             }
2082
2083             pdb.setFile(param);
2084
2085             if (seqs != null)
2086             {
2087               for (int i = 0; i < seqs.length; i++)
2088               {
2089                 if (seqs[i] != null)
2090                 {
2091                   ((Sequence) seqs[i]).addPDBId(pdb);
2092                 }
2093                 else
2094                 {
2095                   if (JalviewLite.debug)
2096                   {
2097                     // this may not really be a problem but we give a warning
2098                     // anyway
2099                     System.err
2100                             .println("Warning: Possible input parsing error: Null sequence for attachment of PDB (sequence "
2101                                     + i + ")");
2102                   }
2103                 }
2104               }
2105
2106               if (!alignPdbStructures)
2107               {
2108                 newAlignFrame.newStructureView(applet, pdb, seqs, chains,
2109                         protocol);
2110               }
2111               else
2112               {
2113                 pdbs.addElement(new Object[]
2114                 { pdb, seqs, chains, new String(protocol) });
2115               }
2116             }
2117           }
2118
2119           pdbFileCount++;
2120         } while (param != null || pdbFileCount < 10);
2121         if (pdbs.size() > 0)
2122         {
2123           SequenceI[][] seqs = new SequenceI[pdbs.size()][];
2124           PDBEntry[] pdb = new PDBEntry[pdbs.size()];
2125           String[][] chains = new String[pdbs.size()][];
2126           String[] protocols = new String[pdbs.size()];
2127           for (int pdbsi = 0, pdbsiSize = pdbs.size(); pdbsi < pdbsiSize; pdbsi++)
2128           {
2129             Object[] o = (Object[]) pdbs.elementAt(pdbsi);
2130             pdb[pdbsi] = (PDBEntry) o[0];
2131             seqs[pdbsi] = (SequenceI[]) o[1];
2132             chains[pdbsi] = (String[]) o[2];
2133             protocols[pdbsi] = (String) o[3];
2134           }
2135           newAlignFrame.alignedStructureView(applet, pdb, seqs, chains,
2136                   protocols);
2137
2138         }
2139       }
2140       else
2141       {
2142         fileFound = false;
2143         applet.remove(launcher);
2144         applet.repaint();
2145       }
2146       callInitCallback();
2147     }
2148
2149     /**
2150      * Discovers whether the given file is in the Applet Archive
2151      * 
2152      * @param file
2153      *          String
2154      * @return boolean
2155      */
2156     boolean inArchive(String file)
2157     {
2158       // This might throw a security exception in certain browsers
2159       // Netscape Communicator for instance.
2160       try
2161       {
2162         boolean rtn = (getClass().getResourceAsStream("/" + file) != null);
2163         if (debug)
2164         {
2165           System.err.println("Resource '" + file + "' was "
2166                   + (rtn ? "" : "not") + " located by classloader.");
2167         }
2168         return rtn;
2169       } catch (Exception ex)
2170       {
2171         System.out.println("Exception checking resources: " + file + " "
2172                 + ex);
2173         return false;
2174       }
2175     }
2176
2177     String addProtocol(String file)
2178     {
2179       if (file.indexOf("://") == -1)
2180       {
2181         String fl = applet.resolveUrlForLocalOrAbsolute(file,
2182                 getDocumentBase());
2183         try
2184         {
2185           if (new java.net.URL(fl).openStream() != null)
2186           {
2187             if (debug)
2188             {
2189               System.err.println("Prepended document base for resource: '"
2190                       + file + "'");
2191             }
2192             return fl;
2193           }
2194         } catch (Exception x)
2195         {
2196         }
2197         ;
2198         fl = applet.resolveUrlForLocalOrAbsolute(file, getCodeBase());
2199         try
2200         {
2201           if (new java.net.URL(fl).openStream() != null)
2202           {
2203             if (debug)
2204             {
2205               System.err.println("Prepended codebase for resource: '"
2206                       + file + "'");
2207             }
2208             return fl;
2209           }
2210         } catch (Exception x)
2211         {
2212         }
2213         ;
2214
2215       }
2216
2217       return file;
2218     }
2219   }
2220
2221   /**
2222    * @return the default alignFrame acted on by the public applet methods. May
2223    *         return null with an error message on System.err indicating the
2224    *         fact.
2225    */
2226   public AlignFrame getDefaultTargetFrame()
2227   {
2228     if (currentAlignFrame != null)
2229     {
2230       return currentAlignFrame;
2231     }
2232     if (initialAlignFrame != null)
2233     {
2234       return initialAlignFrame;
2235     }
2236     System.err
2237             .println("Implementation error: Jalview Applet API cannot work out which AlignFrame to use.");
2238     return null;
2239   }
2240
2241   /**
2242    * separator used for separatorList
2243    */
2244   protected String separator = "" + ((char) 0x00AC); // the default used to be
2245                                                      // '|' but many sequence
2246                                                      // IDS include pipes.
2247
2248   /**
2249    * set to enable the URL based javascript execution mechanism
2250    */
2251   public boolean jsfallbackEnabled = false;
2252
2253   /**
2254    * parse the string into a list
2255    * 
2256    * @param list
2257    * @return elements separated by separator
2258    */
2259   public String[] separatorListToArray(String list)
2260   {
2261     return separatorListToArray(list, separator);
2262   }
2263
2264   /**
2265    * parse the string into a list
2266    * 
2267    * @param list
2268    * @param separator
2269    * @return elements separated by separator
2270    */
2271   public String[] separatorListToArray(String list, String separator)
2272   {
2273     // note separator local variable intentionally masks object field
2274     int seplen = separator.length();
2275     if (list == null || list.equals("") || list.equals(separator))
2276       return null;
2277     java.util.Vector jv = new Vector();
2278     int cp = 0, pos;
2279     while ((pos = list.indexOf(separator, cp)) > cp)
2280     {
2281       jv.addElement(list.substring(cp, pos));
2282       cp = pos + seplen;
2283     }
2284     if (cp < list.length())
2285     {
2286       String c = list.substring(cp);
2287       if (!c.equals(separator))
2288       {
2289         jv.addElement(c);
2290       }
2291     }
2292     if (jv.size() > 0)
2293     {
2294       String[] v = new String[jv.size()];
2295       for (int i = 0; i < v.length; i++)
2296       {
2297         v[i] = (String) jv.elementAt(i);
2298       }
2299       jv.removeAllElements();
2300       if (debug)
2301       {
2302         System.err.println("Array from '" + separator
2303                 + "' separated List:\n" + v.length);
2304         for (int i = 0; i < v.length; i++)
2305         {
2306           System.err.println("item " + i + " '" + v[i] + "'");
2307         }
2308       }
2309       return v;
2310     }
2311     if (debug)
2312     {
2313       System.err.println("Empty Array from '" + separator
2314               + "' separated List");
2315     }
2316     return null;
2317   }
2318
2319   /**
2320    * concatenate the list with separator
2321    * 
2322    * @param list
2323    * @return concatenated string
2324    */
2325   public String arrayToSeparatorList(String[] list)
2326   {
2327     return arrayToSeparatorList(list, separator);
2328   }
2329
2330   /**
2331    * concatenate the list with separator
2332    * 
2333    * @param list
2334    * @param separator
2335    * @return concatenated string
2336    */
2337   public String arrayToSeparatorList(String[] list, String separator)
2338   {
2339     StringBuffer v = new StringBuffer();
2340     if (list != null && list.length > 0)
2341     {
2342       for (int i = 0, iSize = list.length; i < iSize; i++)
2343       {
2344         if (list[i] != null)
2345         {
2346           if (i > 0)
2347           {
2348             v.append(separator);
2349           }
2350           v.append(list[i]);
2351         }
2352       }
2353       if (debug)
2354       {
2355         System.err.println("Returning '" + separator
2356                 + "' separated List:\n");
2357         System.err.println(v);
2358       }
2359       return v.toString();
2360     }
2361     if (debug)
2362     {
2363       System.err.println("Returning empty '" + separator
2364               + "' separated List\n");
2365     }
2366     return "" + separator;
2367   }
2368
2369   /*
2370    * (non-Javadoc)
2371    * 
2372    * @see jalview.bin.JalviewLiteJsApi#getFeatureGroups()
2373    */
2374   public String getFeatureGroups()
2375   {
2376     String lst = arrayToSeparatorList(getDefaultTargetFrame()
2377             .getFeatureGroups());
2378     return lst;
2379   }
2380
2381   /*
2382    * (non-Javadoc)
2383    * 
2384    * @see
2385    * jalview.bin.JalviewLiteJsApi#getFeatureGroupsOn(jalview.appletgui.AlignFrame
2386    * )
2387    */
2388   public String getFeatureGroupsOn(AlignFrame alf)
2389   {
2390     String lst = arrayToSeparatorList(alf.getFeatureGroups());
2391     return lst;
2392   }
2393
2394   /*
2395    * (non-Javadoc)
2396    * 
2397    * @see jalview.bin.JalviewLiteJsApi#getFeatureGroupsOfState(boolean)
2398    */
2399   public String getFeatureGroupsOfState(boolean visible)
2400   {
2401     return arrayToSeparatorList(getDefaultTargetFrame()
2402             .getFeatureGroupsOfState(visible));
2403   }
2404
2405   /*
2406    * (non-Javadoc)
2407    * 
2408    * @see
2409    * jalview.bin.JalviewLiteJsApi#getFeatureGroupsOfStateOn(jalview.appletgui
2410    * .AlignFrame, boolean)
2411    */
2412   public String getFeatureGroupsOfStateOn(AlignFrame alf, boolean visible)
2413   {
2414     return arrayToSeparatorList(alf.getFeatureGroupsOfState(visible));
2415   }
2416
2417   /*
2418    * (non-Javadoc)
2419    * 
2420    * @see jalview.bin.JalviewLiteJsApi#setFeatureGroupStateOn(jalview.appletgui.
2421    * AlignFrame, java.lang.String, boolean)
2422    */
2423   public void setFeatureGroupStateOn(final AlignFrame alf,
2424           final String groups, boolean state)
2425   {
2426     final boolean st = state;// !(state==null || state.equals("") ||
2427     // state.toLowerCase().equals("false"));
2428     java.awt.EventQueue.invokeLater(new Runnable()
2429     {
2430       @Override
2431       public void run()
2432       {
2433         alf.setFeatureGroupState(separatorListToArray(groups), st);
2434       }
2435     });
2436   }
2437
2438   /*
2439    * (non-Javadoc)
2440    * 
2441    * @see jalview.bin.JalviewLiteJsApi#setFeatureGroupState(java.lang.String,
2442    * boolean)
2443    */
2444   public void setFeatureGroupState(String groups, boolean state)
2445   {
2446     setFeatureGroupStateOn(getDefaultTargetFrame(), groups, state);
2447   }
2448
2449   /*
2450    * (non-Javadoc)
2451    * 
2452    * @see jalview.bin.JalviewLiteJsApi#getSeparator()
2453    */
2454   public String getSeparator()
2455   {
2456     return separator;
2457   }
2458
2459   /*
2460    * (non-Javadoc)
2461    * 
2462    * @see jalview.bin.JalviewLiteJsApi#setSeparator(java.lang.String)
2463    */
2464   public void setSeparator(String separator)
2465   {
2466     if (separator == null || separator.length() < 1)
2467     {
2468       // reset to default
2469       separator = "" + ((char) 0x00AC);
2470     }
2471     this.separator = separator;
2472     if (debug)
2473     {
2474       System.err.println("Default Separator now: '" + separator + "'");
2475     }
2476   }
2477
2478   /**
2479    * get boolean value of applet parameter 'name' and return default if
2480    * parameter is not set
2481    * 
2482    * @param name
2483    *          name of paremeter
2484    * @param def
2485    *          the value to return otherwise
2486    * @return true or false
2487    */
2488   public boolean getDefaultParameter(String name, boolean def)
2489   {
2490     String stn;
2491     if ((stn = getParameter(name)) == null)
2492     {
2493       return def;
2494     }
2495     if (stn.toLowerCase().equals("true"))
2496     {
2497       return true;
2498     }
2499     return false;
2500   }
2501
2502   /*
2503    * (non-Javadoc)
2504    * 
2505    * @see jalview.bin.JalviewLiteJsApi#addPdbFile(jalview.appletgui.AlignFrame,
2506    * java.lang.String, java.lang.String, java.lang.String)
2507    */
2508   public boolean addPdbFile(AlignFrame alFrame, String sequenceId,
2509           String pdbEntryString, String pdbFile)
2510   {
2511     return alFrame.addPdbFile(sequenceId, pdbEntryString, pdbFile);
2512   }
2513
2514   protected void setAlignPdbStructures(boolean alignPdbStructures)
2515   {
2516     this.alignPdbStructures = alignPdbStructures;
2517   }
2518
2519   public boolean isAlignPdbStructures()
2520   {
2521     return alignPdbStructures;
2522   }
2523
2524   public void start()
2525   {
2526     // callInitCallback();
2527   }
2528
2529   private Hashtable<String, long[]> jshashes = new Hashtable<String, long[]>();
2530
2531   private Hashtable<String, Hashtable<String, String[]>> jsmessages = new Hashtable<String, Hashtable<String, String[]>>();
2532
2533   public void setJsMessageSet(String messageclass, String viewId,
2534           String[] colcommands)
2535   {
2536     Hashtable<String, String[]> msgset = jsmessages.get(messageclass);
2537     if (msgset == null)
2538     {
2539       msgset = new Hashtable<String, String[]>();
2540       jsmessages.put(messageclass, msgset);
2541     }
2542     msgset.put(viewId, colcommands);
2543     long[] l = new long[colcommands.length];
2544     for (int i = 0; i < colcommands.length; i++)
2545     {
2546       l[i] = colcommands[i].hashCode();
2547     }
2548     jshashes.put(messageclass + "|" + viewId, l);
2549   }
2550
2551   /*
2552    * (non-Javadoc)
2553    * 
2554    * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String,
2555    * java.lang.String)
2556    */
2557   public String getJsMessage(String messageclass, String viewId)
2558   {
2559     Hashtable<String, String[]> msgset = jsmessages.get(messageclass);
2560     if (msgset != null)
2561     {
2562       String[] msgs = msgset.get(viewId);
2563       if (msgs != null)
2564       {
2565         for (int i = 0; i < msgs.length; i++)
2566         {
2567           if (msgs[i] != null)
2568           {
2569             String m = msgs[i];
2570             msgs[i] = null;
2571             return m;
2572           }
2573         }
2574       }
2575     }
2576     return "";
2577   }
2578
2579   public boolean isJsMessageSetChanged(String string, String string2,
2580           String[] colcommands)
2581   {
2582     long[] l = jshashes.get(string + "|" + string2);
2583     if (l == null && colcommands != null)
2584     {
2585       return true;
2586     }
2587     for (int i = 0; i < colcommands.length; i++)
2588     {
2589       if (l[i] != colcommands[i].hashCode())
2590       {
2591         return true;
2592       }
2593     }
2594     return false;
2595   }
2596
2597   private Vector jsExecQueue = new Vector();
2598
2599   public Vector getJsExecQueue()
2600   {
2601     return jsExecQueue;
2602   }
2603
2604   public void setExecutor(JSFunctionExec jsFunctionExec2)
2605   {
2606     jsFunctionExec = jsFunctionExec2;
2607   }
2608
2609   /**
2610    * return the given colour value parameter or the given default if parameter
2611    * not given
2612    * 
2613    * @param colparam
2614    * @param defcolour
2615    * @return
2616    */
2617   public Color getDefaultColourParameter(String colparam, Color defcolour)
2618   {
2619     String colprop = getParameter(colparam);
2620     if (colprop == null || colprop.trim().length() == 0)
2621     {
2622       return defcolour;
2623     }
2624     Color col = jalview.schemes.ColourSchemeProperty
2625             .getAWTColorFromName(colprop);
2626     if (col == null)
2627     {
2628       try
2629       {
2630         col = new jalview.schemes.UserColourScheme(colprop).findColour('A');
2631       } catch (Exception ex)
2632       {
2633         System.err.println("Couldn't parse '" + colprop
2634                 + "' as a colour for " + colparam);
2635         col = null;
2636       }
2637     }
2638     return (col == null) ? defcolour : col;
2639
2640   }
2641
2642   public void openJalviewHelpUrl()
2643   {
2644     String helpUrl = getParameter("jalviewhelpurl");
2645     if (helpUrl == null || helpUrl.trim().length() < 5)
2646     {
2647       helpUrl = "http://www.jalview.org/help.html";
2648     }
2649     showURL(helpUrl, "HELP");
2650   }
2651
2652   /**
2653    * form a complete URL given a path to a resource and a reference location on
2654    * the same server
2655    * 
2656    * @param url
2657    *          - an absolute path on the same server as localref or a document
2658    *          located relative to localref
2659    * @param localref
2660    *          - a URL on the same server as url
2661    * @return a complete URL for the resource located by url
2662    */
2663   private String resolveUrlForLocalOrAbsolute(String url, URL localref)
2664   {
2665     String codebase = localref.toString();
2666     if (url.indexOf("/") == 0)
2667     {
2668       url = codebase.substring(0, codebase.length()
2669               - localref.getFile().length())
2670               + url;
2671     }
2672     else
2673     {
2674       url = localref + url;
2675     }
2676     return url;
2677   }
2678
2679   /**
2680    * open a URL in the browser - resolving it according to relative refs and
2681    * coping with javascript: protocol if necessary.
2682    * 
2683    * @param url
2684    * @param target
2685    */
2686   public void showURL(String url, String target)
2687   {
2688     try
2689     {
2690       if (url.indexOf(":") == -1)
2691       {
2692         // TODO: verify (Bas Vroling bug) prepend codebase or server URL to
2693         // form valid URL
2694         // Should really use docbase, not codebase.
2695         URL prepend;
2696         url = resolveUrlForLocalOrAbsolute(
2697                 url,
2698                 prepend = getDefaultParameter("resolvetocodebase", false) ? getDocumentBase()
2699                         : getCodeBase());
2700         if (debug)
2701         {
2702           System.err
2703                   .println("Show url (prepended "
2704                           + prepend
2705                           + " - toggle resolvetocodebase if code/docbase resolution is wrong): "
2706                           + url);
2707         }
2708       }
2709       else
2710       {
2711         if (debug)
2712         {
2713           System.err.println("Show url: " + url);
2714         }
2715       }
2716       if (url.indexOf("javascript:") == 0)
2717       {
2718         // no target for the javascript context
2719         getAppletContext().showDocument(new java.net.URL(url));
2720       }
2721       else
2722       {
2723         getAppletContext().showDocument(new java.net.URL(url), target);
2724       }
2725     } catch (Exception ex)
2726     {
2727       ex.printStackTrace();
2728     }
2729   }
2730
2731   /**
2732    * bind structures in a viewer to any matching sequences in an alignFrame (use
2733    * sequenceIds to limit scope of search to specific sequences)
2734    * 
2735    * @param alFrame
2736    * @param viewer
2737    * @param sequenceIds
2738    * @return TODO: consider making an exception structure for indicating when
2739    *         binding fails public SequenceStructureBinding
2740    *         addStructureViewInstance( AlignFrame alFrame, Object viewer, String
2741    *         sequenceIds) {
2742    * 
2743    *         if (sequenceIds != null && sequenceIds.length() > 0) { return
2744    *         alFrame.addStructureViewInstance(viewer,
2745    *         separatorListToArray(sequenceIds)); } else { return
2746    *         alFrame.addStructureViewInstance(viewer, null); } // return null; }
2747    */
2748 }