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