JAL-1162 catch security exception and just use bare modelFileName string for applet
[jalview.git] / src / jalview / ext / jmol / JalviewJmolBinding.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  * \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 package jalview.ext.jmol;\r
19 \r
20 import jalview.api.AlignmentViewPanel;\r
21 import jalview.api.FeatureRenderer;\r
22 import jalview.api.SequenceRenderer;\r
23 import jalview.api.SequenceStructureBinding;\r
24 import jalview.api.StructureSelectionManagerProvider;\r
25 import jalview.datamodel.AlignmentI;\r
26 import jalview.datamodel.ColumnSelection;\r
27 import jalview.datamodel.PDBEntry;\r
28 import jalview.datamodel.SequenceI;\r
29 import jalview.io.AppletFormatAdapter;\r
30 import jalview.schemes.ColourSchemeI;\r
31 import jalview.schemes.ResidueProperties;\r
32 import jalview.structure.StructureListener;\r
33 import jalview.structure.StructureMapping;\r
34 import jalview.structure.StructureSelectionManager;\r
35 \r
36 import java.awt.Color;\r
37 import java.awt.Container;\r
38 import java.awt.event.ComponentEvent;\r
39 import java.awt.event.ComponentListener;\r
40 import java.io.File;\r
41 import java.net.URL;\r
42 import java.security.AccessControlException;\r
43 import java.util.Enumeration;\r
44 import java.util.Hashtable;\r
45 import java.util.Map;\r
46 import java.util.Vector;\r
47 \r
48 import org.jmol.adapter.smarter.SmarterJmolAdapter;\r
49 import org.jmol.api.JmolAppConsoleInterface;\r
50 import org.jmol.api.JmolSelectionListener;\r
51 import org.jmol.api.JmolStatusListener;\r
52 import org.jmol.api.JmolViewer;\r
53 import org.jmol.constant.EnumCallback;\r
54 import org.jmol.popup.JmolPopup;\r
55 \r
56 public abstract class JalviewJmolBinding implements StructureListener,\r
57         JmolStatusListener, SequenceStructureBinding,\r
58         JmolSelectionListener, ComponentListener, StructureSelectionManagerProvider\r
59 \r
60 {\r
61   /**\r
62    * set if Jmol state is being restored from some source - instructs binding\r
63    * not to apply default display style when structure set is updated for first\r
64    * time.\r
65    */\r
66   private boolean loadingFromArchive = false;\r
67 \r
68   /**\r
69    * state flag used to check if the Jmol viewer's paint method can be called\r
70    */\r
71   private boolean finishedInit = false;\r
72 \r
73   public boolean isFinishedInit()\r
74   {\r
75     return finishedInit;\r
76   }\r
77 \r
78   public void setFinishedInit(boolean finishedInit)\r
79   {\r
80     this.finishedInit = finishedInit;\r
81   }\r
82 \r
83   boolean allChainsSelected = false;\r
84 \r
85   /**\r
86    * when true, try to search the associated datamodel for sequences that are\r
87    * associated with any unknown structures in the Jmol view.\r
88    */\r
89   private boolean associateNewStructs = false;\r
90 \r
91   Vector atomsPicked = new Vector();\r
92 \r
93   public Vector chainNames;\r
94 \r
95   Hashtable chainFile;\r
96 \r
97   /**\r
98    * array of target chains for seuqences - tied to pdbentry and sequence[]\r
99    */\r
100   protected String[][] chains;\r
101 \r
102   boolean colourBySequence = true;\r
103 \r
104   StringBuffer eval = new StringBuffer();\r
105 \r
106   public String fileLoadingError;\r
107 \r
108   /**\r
109    * the default or current model displayed if the model cannot be identified\r
110    * from the selection message\r
111    */\r
112   int frameNo = 0;\r
113 \r
114   protected JmolPopup jmolpopup;\r
115 \r
116   String lastCommand;\r
117 \r
118   String lastMessage;\r
119 \r
120   boolean loadedInline;\r
121 \r
122   /**\r
123    * current set of model filenames loaded in the Jmol instance\r
124    */\r
125   String[] modelFileNames = null;\r
126 \r
127   public PDBEntry[] pdbentry;\r
128 \r
129   /**\r
130    * datasource protocol for access to PDBEntrylatest\r
131    */\r
132   String protocol = null;\r
133 \r
134   StringBuffer resetLastRes = new StringBuffer();\r
135 \r
136   /**\r
137    * sequences mapped to each pdbentry\r
138    */\r
139   public SequenceI[][] sequence;\r
140 \r
141   public StructureSelectionManager ssm;\r
142 \r
143   public JmolViewer viewer;\r
144 \r
145   public JalviewJmolBinding(StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs,\r
146           String[][] chains, String protocol)\r
147   {\r
148     this.ssm = ssm;\r
149     this.sequence = sequenceIs;\r
150     this.chains = chains;\r
151     this.pdbentry = pdbentry;\r
152     this.protocol = protocol;\r
153     if (chains == null)\r
154     {\r
155       this.chains = new String[pdbentry.length][];\r
156     }\r
157     /*\r
158      * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),\r
159      * "jalviewJmol", ap.av.applet .getDocumentBase(),\r
160      * ap.av.applet.getCodeBase(), "", this);\r
161      * \r
162      * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);\r
163      */\r
164   }\r
165 \r
166   public JalviewJmolBinding(StructureSelectionManager ssm, JmolViewer viewer2)\r
167   {\r
168     this.ssm = ssm;\r
169     viewer = viewer2;\r
170     viewer.setJmolStatusListener(this);\r
171     viewer.addSelectionListener(this);\r
172   }\r
173 \r
174   /**\r
175    * construct a title string for the viewer window based on the data jalview\r
176    * knows about\r
177    * \r
178    * @return\r
179    */\r
180   public String getViewerTitle()\r
181   {\r
182     if (sequence == null || pdbentry == null || sequence.length < 1\r
183             || pdbentry.length < 1 || sequence[0].length < 1)\r
184     {\r
185       return ("Jalview Jmol Window");\r
186     }\r
187     // TODO: give a more informative title when multiple structures are\r
188     // displayed.\r
189     StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"\r
190             + pdbentry[0].getId());\r
191 \r
192     if (pdbentry[0].getProperty() != null)\r
193     {\r
194       if (pdbentry[0].getProperty().get("method") != null)\r
195       {\r
196         title.append(" Method: ");\r
197         title.append(pdbentry[0].getProperty().get("method"));\r
198       }\r
199       if (pdbentry[0].getProperty().get("chains") != null)\r
200       {\r
201         title.append(" Chain:");\r
202         title.append(pdbentry[0].getProperty().get("chains"));\r
203       }\r
204     }\r
205     return title.toString();\r
206   }\r
207 \r
208   /**\r
209    * prepare the view for a given set of models/chains. chainList contains\r
210    * strings of the form 'pdbfilename:Chaincode'\r
211    * \r
212    * @param chainList\r
213    *          list of chains to make visible\r
214    */\r
215   public void centerViewer(Vector chainList)\r
216   {\r
217     StringBuffer cmd = new StringBuffer();\r
218     String lbl;\r
219     int mlength, p;\r
220     for (int i = 0, iSize = chainList.size(); i < iSize; i++)\r
221     {\r
222       mlength = 0;\r
223       lbl = (String) chainList.elementAt(i);\r
224       do\r
225       {\r
226         p = mlength;\r
227         mlength = lbl.indexOf(":", p);\r
228       } while (p < mlength && mlength < (lbl.length() - 2));\r
229       // TODO: lookup each pdb id and recover proper model number for it.\r
230       cmd.append(":" + lbl.substring(mlength + 1) + " /"\r
231               + (1 + getModelNum((String) chainFile.get(lbl))) + " or ");\r
232     }\r
233     if (cmd.length() > 0)\r
234       cmd.setLength(cmd.length() - 4);\r
235     evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);\r
236   }\r
237 \r
238   public void closeViewer()\r
239   {\r
240     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);\r
241     // remove listeners for all structures in viewer\r
242     ssm.removeStructureViewerListener(this, this.getPdbFile());\r
243     // and shut down jmol\r
244     viewer.evalStringQuiet("zap");\r
245     viewer.setJmolStatusListener(null);\r
246     lastCommand = null;\r
247     viewer = null;\r
248     releaseUIResources();\r
249   }\r
250 \r
251   /**\r
252    * called by JalviewJmolbinding after closeViewer is called - release any\r
253    * resources and references so they can be garbage collected.\r
254    */\r
255   protected abstract void releaseUIResources();\r
256 \r
257   public void colourByChain()\r
258   {\r
259     colourBySequence = false;\r
260     // TODO: colour by chain should colour each chain distinctly across all\r
261     // visible models\r
262     // TODO: http://issues.jalview.org/browse/JAL-628\r
263     evalStateCommand("select *;color chain");\r
264   }\r
265 \r
266   public void colourByCharge()\r
267   {\r
268     colourBySequence = false;\r
269     evalStateCommand("select *;color white;select ASP,GLU;color red;"\r
270             + "select LYS,ARG;color blue;select CYS;color yellow");\r
271   }\r
272 \r
273   /**\r
274    * superpose the structures associated with sequences in the alignment\r
275    * according to their corresponding positions.\r
276    */\r
277   public void superposeStructures(AlignmentI alignment)\r
278   {\r
279     superposeStructures(alignment, -1, null);\r
280   }\r
281 \r
282   /**\r
283    * superpose the structures associated with sequences in the alignment\r
284    * according to their corresponding positions. ded)\r
285    * \r
286    * @param refStructure\r
287    *          - select which pdb file to use as reference (default is -1 - the\r
288    *          first structure in the alignment)\r
289    */\r
290   public void superposeStructures(AlignmentI alignment, int refStructure)\r
291   {\r
292     superposeStructures(alignment, refStructure, null);\r
293   }\r
294 \r
295   /**\r
296    * superpose the structures associated with sequences in the alignment\r
297    * according to their corresponding positions. ded)\r
298    * \r
299    * @param refStructure\r
300    *          - select which pdb file to use as reference (default is -1 - the\r
301    *          first structure in the alignment)\r
302    * @param hiddenCols\r
303    *          TODO\r
304    */\r
305   public void superposeStructures(AlignmentI alignment, int refStructure,\r
306           ColumnSelection hiddenCols)\r
307   {\r
308     superposeStructures(new AlignmentI[]\r
309     { alignment }, new int[]\r
310     { refStructure }, new ColumnSelection[]\r
311     { hiddenCols });\r
312   }\r
313 \r
314   public void superposeStructures(AlignmentI[] _alignment,\r
315           int[] _refStructure, ColumnSelection[] _hiddenCols)\r
316   {\r
317     String[] files = getPdbFile();\r
318     StringBuffer selectioncom = new StringBuffer();\r
319     assert (_alignment.length == _refStructure.length && _alignment.length != _hiddenCols.length);\r
320     // union of all aligned positions are collected together.\r
321     for (int a = 0; a < _alignment.length; a++)\r
322     {\r
323       int refStructure = _refStructure[a];\r
324       AlignmentI alignment = _alignment[a];\r
325       ColumnSelection hiddenCols = _hiddenCols[a];\r
326       if (a > 0\r
327               && selectioncom.length() > 0\r
328               && !selectioncom.substring(selectioncom.length() - 1).equals(\r
329                       "|"))\r
330       {\r
331         selectioncom.append("|");\r
332       }\r
333       // process this alignment\r
334       if (refStructure >= files.length)\r
335       {\r
336         System.err.println("Invalid reference structure value "\r
337                 + refStructure);\r
338         refStructure = -1;\r
339       }\r
340       if (refStructure < -1)\r
341       {\r
342         refStructure = -1;\r
343       }\r
344       StringBuffer command = new StringBuffer();\r
345 \r
346       boolean matched[] = new boolean[alignment.getWidth()];\r
347       for (int m = 0; m < matched.length; m++)\r
348       {\r
349 \r
350         matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true;\r
351       }\r
352 \r
353       int commonrpositions[][] = new int[files.length][alignment.getWidth()];\r
354       String isel[] = new String[files.length];\r
355       // reference structure - all others are superposed in it\r
356       String[] targetC = new String[files.length];\r
357       String[] chainNames = new String[files.length];\r
358       for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)\r
359       {\r
360         StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);\r
361         // RACE CONDITION - getMapping only returns Jmol loaded filenames once Jmol callback has completed. \r
362         if (mapping == null || mapping.length < 1)\r
363           continue;\r
364 \r
365         int lastPos = -1;\r
366         for (int s = 0; s < sequence[pdbfnum].length; s++)\r
367         {\r
368           for (int sp, m = 0; m < mapping.length; m++)\r
369           {\r
370             if (mapping[m].getSequence() == sequence[pdbfnum][s]\r
371                     && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)\r
372             {\r
373               if (refStructure == -1)\r
374               {\r
375                 refStructure = pdbfnum;\r
376               }\r
377               SequenceI asp = alignment.getSequenceAt(sp);\r
378               for (int r = 0; r < matched.length; r++)\r
379               {\r
380                 if (!matched[r])\r
381                 {\r
382                   continue;\r
383                 }\r
384                 matched[r] = false; // assume this is not a good site\r
385                 if (r >= asp.getLength())\r
386                 {\r
387                   continue;\r
388                 }\r
389 \r
390                 if (jalview.util.Comparison.isGap(asp.getCharAt(r)))\r
391                 {\r
392                   // no mapping to gaps in sequence\r
393                   continue;\r
394                 }\r
395                 int t = asp.findPosition(r); // sequence position\r
396                 int apos = mapping[m].getAtomNum(t);\r
397                 int pos = mapping[m].getPDBResNum(t);\r
398 \r
399                 if (pos < 1 || pos == lastPos)\r
400                 {\r
401                   // can't align unmapped sequence\r
402                   continue;\r
403                 }\r
404                 matched[r] = true; // this is a good ite\r
405                 lastPos = pos;\r
406                 // just record this residue position\r
407                 commonrpositions[pdbfnum][r] = pos;\r
408               }\r
409               // create model selection suffix\r
410               isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";\r
411               if (mapping[m].getChain() == null\r
412                       || mapping[m].getChain().trim().length() == 0)\r
413               {\r
414                 targetC[pdbfnum] = "";\r
415               }\r
416               else\r
417               {\r
418                 targetC[pdbfnum] = ":" + mapping[m].getChain();\r
419               }\r
420               chainNames[pdbfnum] = mapping[m].getPdbId()\r
421                       + targetC[pdbfnum];\r
422               // move on to next pdb file\r
423               s = sequence[pdbfnum].length;\r
424               break;\r
425             }\r
426           }\r
427         }\r
428       }\r
429       String[] selcom = new String[files.length];\r
430       int nmatched = 0;\r
431       // generate select statements to select regions to superimpose structures\r
432       {\r
433         for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)\r
434         {\r
435           String chainCd = targetC[pdbfnum];\r
436           int lpos = -1;\r
437           boolean run = false;\r
438           StringBuffer molsel = new StringBuffer();\r
439           molsel.append("{");\r
440           for (int r = 0; r < matched.length; r++)\r
441           {\r
442             if (matched[r])\r
443             {\r
444               if (pdbfnum == 0)\r
445               {\r
446                 nmatched++;\r
447               }\r
448               if (lpos != commonrpositions[pdbfnum][r] - 1)\r
449               {\r
450                 // discontinuity\r
451                 if (lpos != -1)\r
452                 {\r
453                   molsel.append(lpos);\r
454                   molsel.append(chainCd);\r
455                   // molsel.append("} {");\r
456                   molsel.append("|");\r
457                 }\r
458               }\r
459               else\r
460               {\r
461                 // continuous run - and lpos >-1\r
462                 if (!run)\r
463                 {\r
464                   // at the beginning, so add dash\r
465                   molsel.append(lpos);\r
466                   molsel.append("-");\r
467                 }\r
468                 run = true;\r
469               }\r
470               lpos = commonrpositions[pdbfnum][r];\r
471               // molsel.append(lpos);\r
472             }\r
473           }\r
474           // add final selection phrase\r
475           if (lpos != -1)\r
476           {\r
477             molsel.append(lpos);\r
478             molsel.append(chainCd);\r
479             molsel.append("}");\r
480           }\r
481           selcom[pdbfnum] = molsel.toString();\r
482           selectioncom.append("((");\r
483           selectioncom.append(selcom[pdbfnum].substring(1,\r
484                   selcom[pdbfnum].length() - 1));\r
485           selectioncom.append(" )& ");\r
486           selectioncom.append(pdbfnum + 1);\r
487           selectioncom.append(".1)");\r
488           if (pdbfnum < files.length - 1)\r
489           {\r
490             selectioncom.append("|");\r
491           }\r
492         }\r
493       }\r
494       // TODO: consider bailing if nmatched less than 4 because superposition\r
495       // not\r
496       // well defined.\r
497       // TODO: refactor superposable position search (above) from jmol selection\r
498       // construction (below)\r
499       for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)\r
500       {\r
501         if (pdbfnum == refStructure)\r
502         {\r
503           continue;\r
504         }\r
505         command.append("echo ");\r
506         command.append("\"Superposing (");\r
507         command.append(chainNames[pdbfnum]);\r
508         command.append(") against reference (");\r
509         command.append(chainNames[refStructure]);\r
510         command.append(")\";\ncompare ");\r
511         command.append("{");\r
512         command.append(1 + pdbfnum);\r
513         command.append(".1} {");\r
514         command.append(1 + refStructure);\r
515         command.append(".1} SUBSET {*.CA | *.P} ATOMS ");\r
516 \r
517         // form the matched pair strings\r
518         String sep = "";\r
519         for (int s = 0; s < 2; s++)\r
520         {\r
521           command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);\r
522         }\r
523         command.append(" ROTATE TRANSLATE;\n");\r
524       }\r
525       System.out.println("Select regions:\n" + selectioncom.toString());\r
526       evalStateCommand("select *; cartoons off; backbone; select ("\r
527               + selectioncom.toString() + "); cartoons; ");\r
528       // selcom.append("; ribbons; ");\r
529       System.out.println("Superimpose command(s):\n" + command.toString());\r
530 \r
531       evalStateCommand(command.toString());\r
532     }\r
533     if (selectioncom.length() > 0)\r
534     {// finally, mark all regions that were superposed.\r
535       if (selectioncom.substring(selectioncom.length() - 1).equals("|"))\r
536       {\r
537         selectioncom.setLength(selectioncom.length() - 1);\r
538       }\r
539       System.out.println("Select regions:\n" + selectioncom.toString());\r
540       evalStateCommand("select *; cartoons off; backbone; select ("\r
541               + selectioncom.toString() + "); cartoons; ");\r
542       // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());\r
543     }\r
544   }\r
545 \r
546   public void evalStateCommand(String command)\r
547   {\r
548     jmolHistory(false);\r
549     if (lastCommand == null || !lastCommand.equals(command))\r
550     {\r
551       viewer.evalStringQuiet(command + "\n");\r
552     }\r
553     jmolHistory(true);\r
554     lastCommand = command;\r
555   }\r
556 \r
557   /**\r
558    * colour any structures associated with sequences in the given alignment\r
559    * using the getFeatureRenderer() and getSequenceRenderer() renderers but only\r
560    * if colourBySequence is enabled.\r
561    */\r
562   public void colourBySequence(boolean showFeatures,\r
563           jalview.api.AlignmentViewPanel alignmentv)\r
564   {\r
565     if (!colourBySequence)\r
566       return;\r
567     if (ssm == null)\r
568     {\r
569       return;\r
570     }\r
571     String[] files = getPdbFile();\r
572 \r
573     SequenceRenderer sr = getSequenceRenderer(alignmentv);\r
574 \r
575     FeatureRenderer fr = null;\r
576     if (showFeatures)\r
577     {\r
578       fr = getFeatureRenderer(alignmentv);\r
579     }\r
580     AlignmentI alignment = alignmentv.getAlignment();\r
581 \r
582     for (jalview.structure.StructureMappingcommandSet cpdbbyseq: JmolCommands.getColourBySequenceCommand(ssm, files, sequence, sr, fr, alignment))\r
583       for (String cbyseq : cpdbbyseq.commands) {\r
584       evalStateCommand(cbyseq);\r
585     }\r
586   }\r
587   \r
588   public boolean isColourBySequence()\r
589   {\r
590     return colourBySequence;\r
591   }\r
592 \r
593   public void setColourBySequence(boolean colourBySequence)\r
594   {\r
595     this.colourBySequence = colourBySequence;\r
596   }\r
597 \r
598   public void createImage(String file, String type, int quality)\r
599   {\r
600     System.out.println("JMOL CREATE IMAGE");\r
601   }\r
602 \r
603   public String createImage(String fileName, String type,\r
604           Object textOrBytes, int quality)\r
605   {\r
606     System.out.println("JMOL CREATE IMAGE");\r
607     return null;\r
608   }\r
609 \r
610   public String eval(String strEval)\r
611   {\r
612     // System.out.println(strEval);\r
613     // "# 'eval' is implemented only for the applet.";\r
614     return null;\r
615   }\r
616 \r
617   // End StructureListener\r
618   // //////////////////////////\r
619 \r
620   public float[][] functionXY(String functionName, int x, int y)\r
621   {\r
622     return null;\r
623   }\r
624 \r
625   public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)\r
626   {\r
627     // TODO Auto-generated method stub\r
628     return null;\r
629   }\r
630 \r
631   public Color getColour(int atomIndex, int pdbResNum, String chain,\r
632           String pdbfile)\r
633   {\r
634     if (getModelNum(pdbfile) < 0)\r
635       return null;\r
636     // TODO: verify atomIndex is selecting correct model.\r
637     return new Color(viewer.getAtomArgb(atomIndex));\r
638   }\r
639 \r
640   /**\r
641    * returns the current featureRenderer that should be used to colour the\r
642    * structures\r
643    * \r
644    * @param alignment\r
645    * \r
646    * @return\r
647    */\r
648   public abstract FeatureRenderer getFeatureRenderer(\r
649           AlignmentViewPanel alignment);\r
650 \r
651   /**\r
652    * instruct the Jalview binding to update the pdbentries vector if necessary\r
653    * prior to matching the jmol view's contents to the list of structure files\r
654    * Jalview knows about.\r
655    */\r
656   public abstract void refreshPdbEntries();\r
657 \r
658   private int getModelNum(String modelFileName)\r
659   {\r
660     String[] mfn = getPdbFile();\r
661     if (mfn == null)\r
662     {\r
663       return -1;\r
664     }\r
665     for (int i = 0; i < mfn.length; i++)\r
666     {\r
667       if (mfn[i].equalsIgnoreCase(modelFileName))\r
668         return i;\r
669     }\r
670     return -1;\r
671   }\r
672 \r
673   /**\r
674    * map between index of model filename returned from getPdbFile and the first\r
675    * index of models from this file in the viewer. Note - this is not trimmed -\r
676    * use getPdbFile to get number of unique models.\r
677    */\r
678   private int _modelFileNameMap[];\r
679 \r
680   // ////////////////////////////////\r
681   // /StructureListener\r
682   public synchronized String[] getPdbFile()\r
683   {\r
684     if (viewer == null)\r
685     {\r
686       return new String[0];\r
687     }\r
688     if (modelFileNames == null)\r
689     {\r
690 \r
691       String mset[] = new String[viewer.getModelCount()];\r
692       _modelFileNameMap = new int[mset.length];\r
693       int j = 1;\r
694       String m=viewer.getModelFileName(0);\r
695       if (m!=null)\r
696       {\r
697         try {\r
698           mset[0] = new File(m).getAbsolutePath();\r
699         } catch (AccessControlException x) {\r
700           // usually not allowed to do this in applet, so keep raw handle\r
701           mset[0] = m;\r
702           //System.err.println("jmolBinding: Using local file string from Jmol: "+m); \r
703         }\r
704       }\r
705       for (int i = 1; i < mset.length; i++)\r
706       {\r
707         m=viewer.getModelFileName(i);\r
708         if (m!=null) {\r
709           try {\r
710             mset[j] = new File(m).getAbsolutePath();\r
711           } catch (AccessControlException x) {\r
712             // usually not allowed to do this in applet, so keep raw handle\r
713             mset[j] = m;\r
714             //System.err.println("jmolBinding: Using local file string from Jmol: "+m); \r
715           }\r
716         }\r
717         _modelFileNameMap[j] = i; // record the model index for the filename\r
718         // skip any additional models in the same file (NMR structures)\r
719         if ((mset[j] == null ? mset[j] != mset[j - 1]\r
720                 : (mset[j - 1] == null || !mset[j].equals(mset[j - 1]))))\r
721         {\r
722           j++;\r
723         }\r
724       }\r
725       modelFileNames = new String[j];\r
726       System.arraycopy(mset, 0, modelFileNames, 0, j);\r
727     }\r
728     return modelFileNames;\r
729   }\r
730 \r
731   /**\r
732    * map from string to applet\r
733    */\r
734   public Map getRegistryInfo()\r
735   {\r
736     // TODO Auto-generated method stub\r
737     return null;\r
738   }\r
739 \r
740   /**\r
741    * returns the current sequenceRenderer that should be used to colour the\r
742    * structures\r
743    * \r
744    * @param alignment\r
745    * \r
746    * @return\r
747    */\r
748   public abstract SequenceRenderer getSequenceRenderer(\r
749           AlignmentViewPanel alignment);\r
750 \r
751   // ///////////////////////////////\r
752   // JmolStatusListener\r
753 \r
754   public void handlePopupMenu(int x, int y)\r
755   {\r
756     jmolpopup.show(x, y);\r
757   }\r
758 \r
759   // jmol/ssm only\r
760   public void highlightAtom(int atomIndex, int pdbResNum, String chain,\r
761           String pdbfile)\r
762   {\r
763     if (modelFileNames == null)\r
764     {\r
765       return;\r
766     }\r
767 \r
768     // look up file model number for this pdbfile\r
769     int mdlNum = 0;\r
770     String fn;\r
771     // may need to adjust for URLencoding here - we don't worry about that yet.\r
772     while (mdlNum < modelFileNames.length\r
773             && !pdbfile.equals(modelFileNames[mdlNum]))\r
774     {\r
775       // System.out.println("nomatch:"+pdbfile+"\nmodelfn:"+fn);\r
776       mdlNum++;\r
777     }\r
778     if (mdlNum == modelFileNames.length)\r
779     {\r
780       return;\r
781     }\r
782 \r
783     jmolHistory(false);\r
784     // if (!pdbfile.equals(pdbentry.getFile()))\r
785     // return;\r
786     if (resetLastRes.length() > 0)\r
787     {\r
788       viewer.evalStringQuiet(resetLastRes.toString());\r
789     }\r
790 \r
791     eval.setLength(0);\r
792     eval.append("select " + pdbResNum); // +modelNum\r
793 \r
794     resetLastRes.setLength(0);\r
795     resetLastRes.append("select " + pdbResNum); // +modelNum\r
796 \r
797     eval.append(":");\r
798     resetLastRes.append(":");\r
799     if (!chain.equals(" "))\r
800     {\r
801       eval.append(chain);\r
802       resetLastRes.append(chain);\r
803     }\r
804     {\r
805       eval.append(" /" + (mdlNum + 1));\r
806       resetLastRes.append("/" + (mdlNum + 1));\r
807     }\r
808     eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");\r
809 \r
810     resetLastRes.append(";wireframe 0;" + resetLastRes.toString()\r
811             + " and not hetero; spacefill 0;");\r
812 \r
813     eval.append("spacefill 200;select none");\r
814 \r
815     viewer.evalStringQuiet(eval.toString());\r
816     jmolHistory(true);\r
817 \r
818   }\r
819 \r
820   boolean debug = true;\r
821 \r
822   private void jmolHistory(boolean enable)\r
823   {\r
824     viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));\r
825   }\r
826 \r
827   public void loadInline(String string)\r
828   {\r
829     loadedInline = true;\r
830     // TODO: re JAL-623\r
831     // viewer.loadInline(strModel, isAppend);\r
832     // could do this:\r
833     // construct fake fullPathName and fileName so we can identify the file\r
834     // later.\r
835     // Then, construct pass a reader for the string to Jmol.\r
836     // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,\r
837     // fileName, null, reader, false, null, null, 0);\r
838     viewer.openStringInline(string);\r
839   }\r
840 \r
841   public void mouseOverStructure(int atomIndex, String strInfo)\r
842   {\r
843     int pdbResNum;\r
844     int alocsep = strInfo.indexOf("^");\r
845     int mdlSep = strInfo.indexOf("/");\r
846     int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;\r
847 \r
848     if (chainSeparator == -1)\r
849     {\r
850       chainSeparator = strInfo.indexOf(".");\r
851       if (mdlSep > -1 && mdlSep < chainSeparator)\r
852       {\r
853         chainSeparator1 = chainSeparator;\r
854         chainSeparator = mdlSep;\r
855       }\r
856     }\r
857     // handle insertion codes\r
858     if (alocsep != -1)\r
859     {\r
860       pdbResNum = Integer.parseInt(strInfo.substring(\r
861               strInfo.indexOf("]") + 1, alocsep));\r
862 \r
863     }\r
864     else\r
865     {\r
866       pdbResNum = Integer.parseInt(strInfo.substring(\r
867               strInfo.indexOf("]") + 1, chainSeparator));\r
868     }\r
869     String chainId;\r
870 \r
871     if (strInfo.indexOf(":") > -1)\r
872       chainId = strInfo.substring(strInfo.indexOf(":") + 1,\r
873               strInfo.indexOf("."));\r
874     else\r
875     {\r
876       chainId = " ";\r
877     }\r
878 \r
879     String pdbfilename = modelFileNames[frameNo]; // default is first or current\r
880     // model\r
881     if (mdlSep > -1)\r
882     {\r
883       if (chainSeparator1 == -1)\r
884       {\r
885         chainSeparator1 = strInfo.indexOf(".", mdlSep);\r
886       }\r
887       String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,\r
888               chainSeparator1) : strInfo.substring(mdlSep + 1);\r
889       try\r
890       {\r
891         // recover PDB filename for the model hovered over.\r
892         int _mp=_modelFileNameMap.length-1,\r
893                 mnumber=new Integer(mdlId).intValue() - 1;\r
894         while(mnumber<_modelFileNameMap[_mp])\r
895         {\r
896           _mp--;\r
897         }\r
898         pdbfilename = modelFileNames[_mp];\r
899         if (pdbfilename==null) {pdbfilename=new File(viewer\r
900                 .getModelFileName(mnumber)).getAbsolutePath();\r
901         }\r
902         \r
903       } catch (Exception e)\r
904       {\r
905       }\r
906       ;\r
907     }\r
908     if (lastMessage == null || !lastMessage.equals(strInfo))\r
909       ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);\r
910 \r
911     lastMessage = strInfo;\r
912   }\r
913 \r
914   public void notifyAtomHovered(int atomIndex, String strInfo, String data)\r
915   {\r
916     if (data != null)\r
917     {\r
918       System.err.println("Ignoring additional hover info: " + data\r
919               + " (other info: '" + strInfo + "' pos " + atomIndex + ")");\r
920     }\r
921     mouseOverStructure(atomIndex, strInfo);\r
922   }\r
923 \r
924   /*\r
925    * { if (history != null && strStatus != null &&\r
926    * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);\r
927    * } }\r
928    */\r
929 \r
930   public void notifyAtomPicked(int atomIndex, String strInfo, String strData)\r
931   {\r
932     /**\r
933      * this implements the toggle label behaviour copied from the original\r
934      * structure viewer, MCView\r
935      */\r
936     if (strData != null)\r
937     {\r
938       System.err.println("Ignoring additional pick data string " + strData);\r
939     }\r
940     int chainSeparator = strInfo.indexOf(":");\r
941     int p = 0;\r
942     if (chainSeparator == -1)\r
943       chainSeparator = strInfo.indexOf(".");\r
944 \r
945     String picked = strInfo.substring(strInfo.indexOf("]") + 1,\r
946             chainSeparator);\r
947     String mdlString = "";\r
948     if ((p = strInfo.indexOf(":")) > -1)\r
949       picked += strInfo.substring(p + 1, strInfo.indexOf("."));\r
950 \r
951     if ((p = strInfo.indexOf("/")) > -1)\r
952     {\r
953       mdlString += strInfo.substring(p, strInfo.indexOf(" #"));\r
954     }\r
955     picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"\r
956             + mdlString + "))";\r
957     jmolHistory(false);\r
958 \r
959     if (!atomsPicked.contains(picked))\r
960     {\r
961       viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");\r
962       atomsPicked.addElement(picked);\r
963     }\r
964     else\r
965     {\r
966       viewer.evalString("select " + picked + ";label off");\r
967       atomsPicked.removeElement(picked);\r
968     }\r
969     jmolHistory(true);\r
970     // TODO: in application this happens\r
971     //\r
972     // if (scriptWindow != null)\r
973     // {\r
974     // scriptWindow.sendConsoleMessage(strInfo);\r
975     // scriptWindow.sendConsoleMessage("\n");\r
976     // }\r
977 \r
978   }\r
979 \r
980   @Override\r
981   public void notifyCallback(EnumCallback type, Object[] data)\r
982   {\r
983     try\r
984     {\r
985       switch (type)\r
986       {\r
987       case LOADSTRUCT:\r
988         notifyFileLoaded((String) data[1], (String) data[2],\r
989                 (String) data[3], (String) data[4],\r
990                 ((Integer) data[5]).intValue());\r
991 \r
992         break;\r
993       case PICK:\r
994         notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],\r
995                 (String) data[0]);\r
996         // also highlight in alignment\r
997       case HOVER:\r
998         notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],\r
999                 (String) data[0]);\r
1000         break;\r
1001       case SCRIPT:\r
1002         notifyScriptTermination((String) data[2],\r
1003                 ((Integer) data[3]).intValue());\r
1004         break;\r
1005       case ECHO:\r
1006         sendConsoleEcho((String) data[1]);\r
1007         break;\r
1008       case MESSAGE:\r
1009         sendConsoleMessage((data == null) ? ((String) null)\r
1010                 : (String) data[1]);\r
1011         break;\r
1012       case ERROR:\r
1013         // System.err.println("Ignoring error callback.");\r
1014         break;\r
1015       case SYNC:\r
1016       case RESIZE:\r
1017         refreshGUI();\r
1018         break;\r
1019       case MEASURE:\r
1020 \r
1021       case CLICK:\r
1022       default:\r
1023         System.err.println("Unhandled callback " + type + " "\r
1024                 + data[1].toString());\r
1025         break;\r
1026       }\r
1027     } catch (Exception e)\r
1028     {\r
1029       System.err.println("Squashed Jmol callback handler error:");\r
1030       e.printStackTrace();\r
1031     }\r
1032   }\r
1033 \r
1034   @Override\r
1035   public boolean notifyEnabled(EnumCallback callbackPick)\r
1036   {\r
1037     switch (callbackPick)\r
1038     {\r
1039     case ECHO:\r
1040     case LOADSTRUCT:\r
1041     case MEASURE:\r
1042     case MESSAGE:\r
1043     case PICK:\r
1044     case SCRIPT:\r
1045     case HOVER:\r
1046     case ERROR:\r
1047       return true;\r
1048     case RESIZE:\r
1049     case SYNC:\r
1050     case CLICK:\r
1051     case ANIMFRAME:\r
1052     case MINIMIZATION:\r
1053     }\r
1054     return false;\r
1055   }\r
1056 \r
1057   // incremented every time a load notification is successfully handled -\r
1058   // lightweight mechanism for other threads to detect when they can start\r
1059   // referrring to new structures.\r
1060   private long loadNotifiesHandled = 0;\r
1061 \r
1062   public long getLoadNotifiesHandled()\r
1063   {\r
1064     return loadNotifiesHandled;\r
1065   }\r
1066 \r
1067   public void notifyFileLoaded(String fullPathName, String fileName2,\r
1068           String modelName, String errorMsg, int modelParts)\r
1069   {\r
1070     if (errorMsg != null)\r
1071     {\r
1072       fileLoadingError = errorMsg;\r
1073       refreshGUI();\r
1074       return;\r
1075     }\r
1076     // TODO: deal sensibly with models loaded inLine:\r
1077     // modelName will be null, as will fullPathName.\r
1078 \r
1079     // the rest of this routine ignores the arguments, and simply interrogates\r
1080     // the Jmol view to find out what structures it contains, and adds them to\r
1081     // the structure selection manager.\r
1082     fileLoadingError = null;\r
1083     String[] oldmodels = modelFileNames;\r
1084     modelFileNames = null;\r
1085     chainNames = new Vector();\r
1086     chainFile = new Hashtable();\r
1087     boolean notifyLoaded = false;\r
1088     String[] modelfilenames = getPdbFile();\r
1089     // first check if we've lost any structures\r
1090     if (oldmodels != null && oldmodels.length > 0)\r
1091     {\r
1092       int oldm = 0;\r
1093       for (int i = 0; i < oldmodels.length; i++)\r
1094       {\r
1095         for (int n = 0; n < modelfilenames.length; n++)\r
1096         {\r
1097           if (modelfilenames[n] == oldmodels[i])\r
1098           {\r
1099             oldmodels[i] = null;\r
1100             break;\r
1101           }\r
1102         }\r
1103         if (oldmodels[i] != null)\r
1104         {\r
1105           oldm++;\r
1106         }\r
1107       }\r
1108       if (oldm > 0)\r
1109       {\r
1110         String[] oldmfn = new String[oldm];\r
1111         oldm = 0;\r
1112         for (int i = 0; i < oldmodels.length; i++)\r
1113         {\r
1114           if (oldmodels[i] != null)\r
1115           {\r
1116             oldmfn[oldm++] = oldmodels[i];\r
1117           }\r
1118         }\r
1119         // deregister the Jmol instance for these structures - we'll add\r
1120         // ourselves again at the end for the current structure set.\r
1121         ssm.removeStructureViewerListener(this, oldmfn);\r
1122       }\r
1123     }\r
1124     refreshPdbEntries();\r
1125     for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)\r
1126     {\r
1127       String fileName = modelfilenames[modelnum];\r
1128       boolean foundEntry = false;\r
1129       MCview.PDBfile pdb = null;\r
1130       String pdbfile = null, pdbfhash = null;\r
1131       // model was probably loaded inline - so check the pdb file hashcode\r
1132       if (loadedInline)\r
1133       {\r
1134         // calculate essential attributes for the pdb data imported inline.\r
1135         // prolly need to resolve modelnumber properly - for now just use our\r
1136         // 'best guess'\r
1137         pdbfile = viewer.getData("" + (1 + _modelFileNameMap[modelnum])\r
1138                 + ".0", "PDB");\r
1139         pdbfhash = "" + pdbfile.hashCode();\r
1140       }\r
1141       if (pdbentry != null)\r
1142       {\r
1143         // search pdbentries and sequences to find correct pdbentry for this\r
1144         // model\r
1145         for (int pe = 0; pe < pdbentry.length; pe++)\r
1146         {\r
1147           boolean matches = false;\r
1148           if (fileName == null)\r
1149           {\r
1150             if (false)\r
1151             // see JAL-623 - need method of matching pasted data up\r
1152             {\r
1153               pdb = ssm.setMapping(sequence[pe], chains[pe], pdbfile,\r
1154                       AppletFormatAdapter.PASTE);\r
1155               pdbentry[modelnum].setFile("INLINE" + pdb.id);\r
1156               matches = true;\r
1157               foundEntry = true;\r
1158             }\r
1159           }\r
1160           else\r
1161           {\r
1162             File fl;\r
1163             if (matches = (fl=new File(pdbentry[pe].getFile())).equals(new File(fileName)))\r
1164             {\r
1165               foundEntry = true;\r
1166               // TODO: Jmol can in principle retrieve from CLASSLOADER but\r
1167               // this\r
1168               // needs\r
1169               // to be tested. See mantis bug\r
1170               // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605\r
1171               String protocol = AppletFormatAdapter.URL;\r
1172               try\r
1173               {\r
1174                 if (fl.exists())\r
1175                 {\r
1176                   protocol = AppletFormatAdapter.FILE;\r
1177                 }\r
1178               } catch (Exception e)\r
1179               {\r
1180               } catch (Error e)\r
1181               {\r
1182               }\r
1183               //Explicitly map to the filename used by Jmol ;\r
1184               pdb = ssm.setMapping(sequence[pe], chains[pe],\r
1185                       fileName, protocol);\r
1186                       //pdbentry[pe].getFile(), protocol);\r
1187 \r
1188             }\r
1189           }\r
1190           if (matches)\r
1191           {\r
1192             // add an entry for every chain in the model\r
1193             for (int i = 0; i < pdb.chains.size(); i++)\r
1194             {\r
1195               String chid = new String(pdb.id + ":"\r
1196                       + ((MCview.PDBChain) pdb.chains.elementAt(i)).id);\r
1197               chainFile.put(chid, fileName);\r
1198               chainNames.addElement(chid);\r
1199             }\r
1200             notifyLoaded = true;\r
1201           }\r
1202         }\r
1203       }\r
1204       if (!foundEntry && associateNewStructs)\r
1205       {\r
1206         // this is a foreign pdb file that jalview doesn't know about - add\r
1207         // it to the dataset and try to find a home - either on a matching\r
1208         // sequence or as a new sequence.\r
1209         String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",\r
1210                 "PDB");\r
1211         // parse pdb file into a chain, etc.\r
1212         // locate best match for pdb in associated views and add mapping to\r
1213         // ssm\r
1214         // if properly registered then\r
1215         notifyLoaded = true;\r
1216 \r
1217       }\r
1218     }\r
1219     // FILE LOADED OK\r
1220     // so finally, update the jmol bits and pieces\r
1221     if (jmolpopup != null)\r
1222     {\r
1223       // potential for deadlock here:\r
1224       // jmolpopup.updateComputedMenus();\r
1225     }\r
1226     if (!isLoadingFromArchive())\r
1227     {\r
1228       viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");\r
1229     }\r
1230     // register ourselves as a listener and notify the gui that it needs to\r
1231     // update itself.\r
1232     ssm.addStructureViewerListener(this);\r
1233     if (notifyLoaded)\r
1234     {\r
1235       FeatureRenderer fr = getFeatureRenderer(null);\r
1236       if (fr != null)\r
1237       {\r
1238         fr.featuresAdded();\r
1239       }\r
1240       refreshGUI();\r
1241       loadNotifiesHandled++;\r
1242     }\r
1243     setLoadingFromArchive(false);\r
1244   }\r
1245 \r
1246   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)\r
1247   {\r
1248     notifyAtomPicked(iatom, strMeasure, null);\r
1249   }\r
1250 \r
1251   public abstract void notifyScriptTermination(String strStatus,\r
1252           int msWalltime);\r
1253 \r
1254   /**\r
1255    * display a message echoed from the jmol viewer\r
1256    * \r
1257    * @param strEcho\r
1258    */\r
1259   public abstract void sendConsoleEcho(String strEcho); /*\r
1260                                                          * { showConsole(true);\r
1261                                                          * \r
1262                                                          * history.append("\n" +\r
1263                                                          * strEcho); }\r
1264                                                          */\r
1265 \r
1266   // /End JmolStatusListener\r
1267   // /////////////////////////////\r
1268 \r
1269   /**\r
1270    * @param strStatus\r
1271    *          status message - usually the response received after a script\r
1272    *          executed\r
1273    */\r
1274   public abstract void sendConsoleMessage(String strStatus);\r
1275 \r
1276   public void setCallbackFunction(String callbackType,\r
1277           String callbackFunction)\r
1278   {\r
1279     System.err.println("Ignoring set-callback request to associate "\r
1280             + callbackType + " with function " + callbackFunction);\r
1281 \r
1282   }\r
1283 \r
1284   public void setJalviewColourScheme(ColourSchemeI cs)\r
1285   {\r
1286     colourBySequence = false;\r
1287 \r
1288     if (cs == null)\r
1289       return;\r
1290 \r
1291     String res;\r
1292     int index;\r
1293     Color col;\r
1294     jmolHistory(false);\r
1295     // TODO: Switch between nucleotide or aa selection expressions\r
1296     Enumeration en = ResidueProperties.aa3Hash.keys();\r
1297     StringBuffer command = new StringBuffer("select *;color white;");\r
1298     while (en.hasMoreElements())\r
1299     {\r
1300       res = en.nextElement().toString();\r
1301       index = ((Integer) ResidueProperties.aa3Hash.get(res)).intValue();\r
1302       if (index > 20)\r
1303         continue;\r
1304 \r
1305       col = cs.findColour(ResidueProperties.aa[index].charAt(0));\r
1306 \r
1307       command.append("select " + res + ";color[" + col.getRed() + ","\r
1308               + col.getGreen() + "," + col.getBlue() + "];");\r
1309     }\r
1310 \r
1311     evalStateCommand(command.toString());\r
1312     jmolHistory(true);\r
1313   }\r
1314 \r
1315   public void showHelp()\r
1316   {\r
1317     showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");\r
1318   }\r
1319 \r
1320   /**\r
1321    * open the URL somehow\r
1322    * \r
1323    * @param target\r
1324    */\r
1325   public abstract void showUrl(String url, String target);\r
1326 \r
1327   /**\r
1328    * called when the binding thinks the UI needs to be refreshed after a Jmol\r
1329    * state change. this could be because structures were loaded, or because an\r
1330    * error has occured.\r
1331    */\r
1332   public abstract void refreshGUI();\r
1333 \r
1334   /**\r
1335    * called to show or hide the associated console window container.\r
1336    * \r
1337    * @param show\r
1338    */\r
1339   public abstract void showConsole(boolean show);\r
1340 \r
1341   /**\r
1342    * @param renderPanel\r
1343    * @param jmolfileio\r
1344    *          - when true will initialise jmol's file IO system (should be false\r
1345    *          in applet context)\r
1346    * @param htmlName\r
1347    * @param documentBase\r
1348    * @param codeBase\r
1349    * @param commandOptions\r
1350    */\r
1351   public void allocateViewer(Container renderPanel, boolean jmolfileio,\r
1352           String htmlName, URL documentBase, URL codeBase,\r
1353           String commandOptions)\r
1354   {\r
1355     allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,\r
1356             codeBase, commandOptions, null, null);\r
1357   }\r
1358 \r
1359   /**\r
1360    * \r
1361    * @param renderPanel\r
1362    * @param jmolfileio\r
1363    *          - when true will initialise jmol's file IO system (should be false\r
1364    *          in applet context)\r
1365    * @param htmlName\r
1366    * @param documentBase\r
1367    * @param codeBase\r
1368    * @param commandOptions\r
1369    * @param consolePanel\r
1370    *          - panel to contain Jmol console\r
1371    * @param buttonsToShow\r
1372    *          - buttons to show on the console, in ordr\r
1373    */\r
1374   public void allocateViewer(Container renderPanel, boolean jmolfileio,\r
1375           String htmlName, URL documentBase, URL codeBase,\r
1376           String commandOptions, final Container consolePanel,\r
1377           String buttonsToShow)\r
1378   {\r
1379     if (commandOptions==null) {
1380       commandOptions="";
1381     }
1382     viewer = JmolViewer.allocateViewer(renderPanel,\r
1383             (jmolfileio ? new SmarterJmolAdapter() : null), htmlName\r
1384                     + ((Object) this).toString(), documentBase, codeBase,\r
1385             commandOptions, this);\r
1386 \r
1387     console = createJmolConsole(viewer, consolePanel, buttonsToShow);\r
1388     if (consolePanel != null)\r
1389     {\r
1390       consolePanel.addComponentListener(this);\r
1391 \r
1392     }\r
1393 \r
1394   }\r
1395 \r
1396   protected abstract JmolAppConsoleInterface createJmolConsole(\r
1397           JmolViewer viewer2, Container consolePanel, String buttonsToShow);\r
1398 \r
1399   protected org.jmol.api.JmolAppConsoleInterface console = null;\r
1400 \r
1401   public void componentResized(ComponentEvent e)\r
1402   {\r
1403 \r
1404   }\r
1405 \r
1406   public void componentMoved(ComponentEvent e)\r
1407   {\r
1408 \r
1409   }\r
1410 \r
1411   public void componentShown(ComponentEvent e)\r
1412   {\r
1413     showConsole(true);\r
1414   }\r
1415 \r
1416   public void componentHidden(ComponentEvent e)\r
1417   {\r
1418     showConsole(false);\r
1419   }\r
1420 \r
1421   public void setLoadingFromArchive(boolean loadingFromArchive)\r
1422   {\r
1423     this.loadingFromArchive = loadingFromArchive;\r
1424   }\r
1425 \r
1426   public boolean isLoadingFromArchive()\r
1427   {\r
1428     return loadingFromArchive;\r
1429   }\r
1430 \r
1431   public void setBackgroundColour(java.awt.Color col)\r
1432   {\r
1433     jmolHistory(false);\r
1434     viewer.evalStringQuiet("background [" + col.getRed() + ","\r
1435             + col.getGreen() + "," + col.getBlue() + "];");\r
1436     jmolHistory(true);\r
1437   }\r
1438 \r
1439   /**\r
1440    * add structures and any known sequence associations\r
1441    * \r
1442    * @returns the pdb entries added to the current set.\r
1443    */\r
1444   public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,\r
1445           SequenceI[][] seq, String[][] chns)\r
1446   {\r
1447     int pe = -1;\r
1448     Vector v = new Vector();\r
1449     Vector rtn = new Vector();\r
1450     for (int i = 0; i < pdbentry.length; i++)\r
1451     {\r
1452       v.addElement(pdbentry[i]);\r
1453     }\r
1454     for (int i = 0; i < pdbe.length; i++)\r
1455     {\r
1456       int r = v.indexOf(pdbe[i]);\r
1457       if (r == -1 || r >= pdbentry.length)\r
1458       {\r
1459         rtn.addElement(new int[]\r
1460         { v.size(), i });\r
1461         v.addElement(pdbe[i]);\r
1462       }\r
1463       else\r
1464       {\r
1465         // just make sure the sequence/chain entries are all up to date\r
1466         addSequenceAndChain(r, seq[i], chns[i]);\r
1467       }\r
1468     }\r
1469     pdbe = new PDBEntry[v.size()];\r
1470     v.copyInto(pdbe);\r
1471     pdbentry = pdbe;\r
1472     if (rtn.size() > 0)\r
1473     {\r
1474       // expand the tied seuqence[] and string[] arrays\r
1475       SequenceI[][] sqs = new SequenceI[pdbentry.length][];\r
1476       String[][] sch = new String[pdbentry.length][];\r
1477       System.arraycopy(sequence, 0, sqs, 0, sequence.length);\r
1478       System.arraycopy(chains, 0, sch, 0, this.chains.length);\r
1479       sequence = sqs;\r
1480       chains = sch;\r
1481       pdbe = new PDBEntry[rtn.size()];\r
1482       for (int r = 0; r < pdbe.length; r++)\r
1483       {\r
1484         int[] stri = ((int[]) rtn.elementAt(r));\r
1485         // record the pdb file as a new addition\r
1486         pdbe[r] = pdbentry[stri[0]];\r
1487         // and add the new sequence/chain entries\r
1488         addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);\r
1489       }\r
1490     }\r
1491     else\r
1492     {\r
1493       pdbe = null;\r
1494     }\r
1495     return pdbe;\r
1496   }\r
1497 \r
1498   public void addSequence(int pe, SequenceI[] seq)\r
1499   {\r
1500     // add sequences to the pe'th pdbentry's seuqence set.\r
1501     addSequenceAndChain(pe, seq, null);\r
1502   }\r
1503 \r
1504   private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)\r
1505   {\r
1506     if (pe < 0 || pe >= pdbentry.length)\r
1507     {\r
1508       throw new Error(\r
1509               "Implementation error - no corresponding pdbentry (for index "\r
1510                       + pe + ") to add sequences mappings to");\r
1511     }\r
1512     final String nullChain = "TheNullChain";\r
1513     Vector s = new Vector();\r
1514     Vector c = new Vector();\r
1515     if (chains == null)\r
1516     {\r
1517       chains = new String[pdbentry.length][];\r
1518     }\r
1519     if (sequence[pe] != null)\r
1520     {\r
1521       for (int i = 0; i < sequence[pe].length; i++)\r
1522       {\r
1523         s.addElement(sequence[pe][i]);\r
1524         if (chains[pe] != null)\r
1525         {\r
1526           if (i < chains[pe].length)\r
1527           {\r
1528             c.addElement(chains[pe][i]);\r
1529           }\r
1530           else\r
1531           {\r
1532             c.addElement(nullChain);\r
1533           }\r
1534         }\r
1535         else\r
1536         {\r
1537           if (tchain != null && tchain.length > 0)\r
1538           {\r
1539             c.addElement(nullChain);\r
1540           }\r
1541         }\r
1542       }\r
1543     }\r
1544     for (int i = 0; i < seq.length; i++)\r
1545     {\r
1546       if (!s.contains(seq[i]))\r
1547       {\r
1548         s.addElement(seq[i]);\r
1549         if (tchain != null && i < tchain.length)\r
1550         {\r
1551           c.addElement(tchain[i] == null ? nullChain : tchain[i]);\r
1552         }\r
1553       }\r
1554     }\r
1555     SequenceI[] tmp = new SequenceI[s.size()];\r
1556     s.copyInto(tmp);\r
1557     sequence[pe] = tmp;\r
1558     if (c.size() > 0)\r
1559     {\r
1560       String[] tch = new String[c.size()];\r
1561       c.copyInto(tch);\r
1562       for (int i = 0; i < tch.length; i++)\r
1563       {\r
1564         if (tch[i] == nullChain)\r
1565         {\r
1566           tch[i] = null;\r
1567         }\r
1568       }\r
1569       chains[pe] = tch;\r
1570     }\r
1571     else\r
1572     {\r
1573       chains[pe] = null;\r
1574     }\r
1575   }\r
1576   /**\r
1577    * \r
1578    * @param pdbfile\r
1579    * @return text report of alignment between pdbfile and any associated alignment sequences\r
1580    */\r
1581   public String printMapping(String pdbfile)\r
1582   {\r
1583     return ssm.printMapping(pdbfile);\r
1584   }\r
1585   @Override\r
1586   public void resizeInnerPanel(String data)\r
1587   {\r
1588     // Jalview doesn't honour resize panel requests\r
1589     \r
1590   }\r
1591 }\r