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