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