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