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