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