Clover icon

Coverage Report

  1. Project Clover database Wed Jan 7 2026 02:39:37 GMT
  2. Package jalview.ext.jmol

File JalviewJmolBinding.java

 

Coverage histogram

../../../img/srcFileCovDistChart6.png
37% of files have more coverage

Code metrics

142
318
49
1
1,177
805
154
0.48
6.49
49
3.14

Classes

Class Line # Actions
JalviewJmolBinding 64 318 154
0.54616954.6%
 

Contributing tests

This file is covered by 60 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.ext.jmol;
22   
23    import java.awt.Container;
24    import java.awt.event.ComponentEvent;
25    import java.awt.event.ComponentListener;
26    import java.io.File;
27    import java.net.URL;
28    import java.util.ArrayList;
29    import java.util.Arrays;
30    import java.util.HashMap;
31    import java.util.List;
32    import java.util.Map;
33    import java.util.StringTokenizer;
34    import java.util.Vector;
35   
36    import javax.swing.SwingUtilities;
37    import org.jmol.adapter.smarter.SmarterJmolAdapter;
38    import org.jmol.api.JmolAppConsoleInterface;
39    import org.jmol.api.JmolSelectionListener;
40    import org.jmol.api.JmolStatusListener;
41    import org.jmol.api.JmolViewer;
42    import org.jmol.c.CBK;
43    import org.jmol.viewer.Viewer;
44   
45    import jalview.api.AlignmentViewPanel;
46    import jalview.api.FeatureRenderer;
47    import jalview.api.FeatureSettingsModelI;
48    import jalview.api.SequenceRenderer;
49    import jalview.bin.Console;
50    import jalview.datamodel.PDBEntry;
51    import jalview.datamodel.SequenceI;
52    import jalview.gui.AppJmol;
53    import jalview.gui.IProgressIndicator;
54    import jalview.gui.StructureViewer.ViewerType;
55    import jalview.io.DataSourceType;
56    import jalview.io.StructureFile;
57    import jalview.structure.AtomSpec;
58    import jalview.structure.StructureCommand;
59    import jalview.structure.StructureCommandI;
60    import jalview.structure.StructureSelectionManager;
61    import jalview.structures.models.AAStructureBindingModel;
62    import jalview.ws.dbsources.Pdb;
63    import javajs.util.BS;
 
64    public abstract class JalviewJmolBinding extends AAStructureBindingModel
65    implements JmolStatusListener, JmolSelectionListener,
66    ComponentListener
67    {
68    private String lastMessage;
69   
70   
71    /*
72    * when true, try to search the associated datamodel for sequences that are
73    * associated with any unknown structures in the Jmol view.
74    */
75    private boolean associateNewStructs = false;
76   
77    private Vector<String> atomsPicked = new Vector<>();
78   
79    private String lastCommand;
80   
81    private boolean loadedInline;
82   
83    private StringBuffer resetLastRes = new StringBuffer();
84   
85    public Viewer jmolViewer;
86   
 
87  48 toggle public JalviewJmolBinding(StructureSelectionManager ssm,
88    PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
89    DataSourceType protocol)
90    {
91  48 super(ssm, pdbentry, sequenceIs, protocol);
92  48 setStructureCommands(new JmolCommands());
93    /*
94    * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
95    * "jalviewJmol", ap.av.applet .getDocumentBase(), ap.av.applet.getCodeBase(),
96    * "", this);
97    *
98    * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
99    */
100    }
101   
 
102  0 toggle public JalviewJmolBinding(StructureSelectionManager ssm,
103    SequenceI[][] seqs, Viewer theViewer)
104    {
105  0 super(ssm, seqs);
106   
107  0 jmolViewer = theViewer;
108  0 jmolViewer.setJmolStatusListener(this);
109  0 jmolViewer.addSelectionListener(this);
110  0 setStructureCommands(new JmolCommands());
111    }
112   
113    /**
114    * construct a title string for the viewer window based on the data jalview
115    * knows about
116    *
117    * @return
118    */
 
119  48 toggle public String getViewerTitle()
120    {
121  48 return getDynamicViewerTitle("Jmol", true);
122    }
123   
 
124  56 toggle private String jmolScript(String script)
125    {
126  56 return jmolScript(script, false);
127    }
128   
 
129  1135 toggle private String jmolScript(String script, boolean useScriptWait)
130    {
131  1135 Console.debug(">>Jmol>> " + script);
132  1135 String s;
133  1135 if (useScriptWait)
134    {
135  3 s = jmolViewer.scriptWait(script);
136    }
137    else
138    {
139  1132 s = jmolViewer.evalStringQuiet(script); // scriptWait(script); BH
140    }
141  1135 Console.debug("<<Jmol<< " + s);
142   
143  1135 return s;
144    }
145   
 
146  422 toggle @Override
147    public List<String> executeCommand(StructureCommandI command,
148    boolean getReply)
149    {
150  422 if (command == null || jmolViewer==null)
151    {
152  5 return null;
153    }
154   
155  417 String cmd = command.getCommand();
156  417 if (cmd==null) {
157  0 return null;
158    }
159  417 jmolHistory(false);
160  417 if (lastCommand == null || !lastCommand.equals(cmd))
161    {
162  245 jmolScript(cmd + "\n", command.isWaitNeeded());
163    }
164  417 jmolHistory(true);
165  417 lastCommand = cmd;
166  417 return null;
167    }
168   
 
169  0 toggle public void createImage(String file, String type, int quality)
170    {
171  0 jalview.bin.Console.outPrintln("JMOL CREATE IMAGE");
172    }
173   
 
174  6 toggle @Override
175    public String createImage(String fileName, String type,
176    Object textOrBytes, int quality)
177    {
178  6 jalview.bin.Console.outPrintln("JMOL CREATE IMAGE");
179  6 return null;
180    }
181   
 
182  0 toggle @Override
183    public String eval(String strEval)
184    {
185    // jalview.bin.Console.outPrintln(strEval);
186    // "# 'eval' is implemented only for the applet.";
187  0 return null;
188    }
189   
190    // End StructureListener
191    // //////////////////////////
192   
193    ////////////////////////////
194    // HETATM get
195    //
196   
 
197  68 toggle @Override
198    public Map<String, String> getHetatmNames()
199    {
200  68 HashMap<String, String> hetlist = new HashMap();
201  161 for (int mc = 0; mc < jmolViewer.ms.mc; mc++)
202    {
203  93 Map<String, String> hets = jmolViewer.ms.getHeteroList(mc);
204  93 if (hets != null)
205    {
206  19 hetlist.putAll(hets);
207    }
208    }
209  68 return hetlist;
210    }
211    //
212    ////////////////////////////
213   
 
214  0 toggle @Override
215    public float[][] functionXY(String functionName, int x, int y)
216    {
217  0 return null;
218    }
219   
 
220  0 toggle @Override
221    public float[][][] functionXYZ(String functionName, int nx, int ny,
222    int nz)
223    {
224    // TODO Auto-generated method stub
225  0 return null;
226    }
227   
228   
229    /**
230    * map between index of model filename returned from getPdbFile and the first
231    * index of models from this file in the viewer. Note - this is not trimmed -
232    * use getPdbFile to get number of unique models.
233    */
234    private int _modelFileNameMap[];
235   
 
236  1121 toggle @Override
237    public synchronized String[] getStructureFiles()
238    {
239  1121 if (jmolViewer == null)
240    {
241  48 return new String[0];
242    }
243   
244  1073 if (modelFileNames == null)
245    {
246  244 int modelCount = jmolViewer.ms.mc;
247  244 String filePath = null;
248  244 List<String> mset = new ArrayList<>();
249  512 for (int i = 0; i < modelCount; ++i)
250    {
251    /*
252    * defensive check for null as getModelFileName can return null even when model
253    * count ms.mc is > 0
254    */
255  268 filePath = jmolViewer.ms.getModelFileName(i);
256  268 if (filePath != null && !mset.contains(filePath))
257    {
258  120 mset.add(filePath);
259    }
260    }
261  244 if (!mset.isEmpty())
262    {
263  96 modelFileNames = mset.toArray(new String[mset.size()]);
264    }
265    }
266   
267  1073 return modelFileNames;
268    }
269   
270    /**
271    * map from string to applet
272    */
 
273  0 toggle @Override
274    public Map<String, Object> getRegistryInfo()
275    {
276    // TODO Auto-generated method stub
277  0 return null;
278    }
279   
280    // ///////////////////////////////
281    // JmolStatusListener
282   
 
283  0 toggle public void handlePopupMenu(int x, int y)
284    {
285    // jmolpopup.show(x, y);
286    // jmolpopup.jpiShow(x, y);
287    }
288   
289    /**
290    * Highlight zero, one or more atoms on the structure
291    */
 
292  0 toggle @Override
293    public void highlightAtoms(List<AtomSpec> atoms)
294    {
295  0 if (atoms != null)
296    {
297  0 if (resetLastRes.length() > 0)
298    {
299  0 jmolScript(resetLastRes.toString());
300  0 resetLastRes.setLength(0);
301    }
302  0 StringBuilder highlightCommands = null;
303  0 for (AtomSpec atom : atoms)
304    {
305  0 StringBuilder thisAtom = highlightAtom(atom.getAtomIndex(),
306    atom.getPdbResNum(), atom.getChain(), atom.getPdbFile());
307  0 if (thisAtom != null)
308    {
309  0 if (highlightCommands == null)
310    {
311  0 highlightCommands = thisAtom;
312    }
313    else
314    {
315  0 highlightCommands.append(thisAtom);
316    }
317    }
318    }
319  0 if (highlightCommands != null)
320    {
321  0 jmolHistory(false);
322  0 jmolScript(highlightCommands.toString());
323  0 jmolHistory(true);
324    }
325    // Highlight distances between atoms with a 'measure' command - not yet
326    // working
327    // if (atoms.size() >= 2)
328    // {
329    // StringBuilder sb = new StringBuilder();
330    // for (int a = 0; a < atoms.size(); a++)
331    // {
332    // AtomSpec speca = atoms.get(a);
333    // String a_model = getModelIdForFile(speca.getPdbFile());
334    // for (int b = a + 1; b < atoms.size(); b++)
335    // {
336    // AtomSpec specb = atoms.get(b);
337    // String b_model = getModelIdForFile(speca.getPdbFile());
338    // sb.append("measure ALL (" + speca.getAtomIndex() + " and */"
339    // + a_model + ") (" + specb.getAtomIndex() + " and */"
340    // + b_model + ");");
341    // }
342    // }
343    // jmolHistory(false, useScriptWait);
344    // jmolScript(sb.toString(), useScriptWait);
345    // jmolHistory(true, useScriptWait);
346    // }
347   
348    }
349   
350    }
351   
352    // jmol/ssm only
 
353  0 toggle private StringBuilder highlightAtom(int atomIndex, int pdbResNum,
354    String chain, String pdbfile)
355    {
356  0 String modelId = getModelIdForFile(pdbfile);
357  0 if (modelId.isEmpty())
358    {
359  0 return null;
360    }
361   
362  0 StringBuilder selection = new StringBuilder(32);
363  0 StringBuilder cmd = new StringBuilder(64);
364  0 selection.append("select ").append(String.valueOf(pdbResNum));
365  0 selection.append(":");
366  0 if (!chain.equals(" "))
367    {
368  0 selection.append(chain);
369    }
370  0 selection.append(" /").append(modelId);
371   
372  0 cmd.append(selection).append(";wireframe 100;").append(selection)
373    .append(" and not hetero;").append("spacefill 200;select none");
374   
375  0 resetLastRes.append(selection).append(";wireframe 0;").append(selection)
376    .append(" and not hetero; spacefill 0;");
377   
378  0 return cmd;
379    }
380   
381    private boolean debug = true;
382   
 
383  834 toggle private void jmolHistory(boolean enable)
384    {
385  834 jmolHistory(enable, false);
386    }
387   
 
388  834 toggle private void jmolHistory(boolean enable, boolean useScriptWait)
389    {
390  834 jmolScript("History " + ((debug || enable) ? "on" : "off"),
391    useScriptWait);
392    }
393   
 
394  0 toggle public void loadInline(String string)
395    {
396  0 loadedInline = true;
397    // TODO: re JAL-623
398    // viewer.loadInline(strModel, isAppend);
399    // could do this:
400    // construct fake fullPathName and fileName so we can identify the file
401    // later.
402    // Then, construct pass a reader for the string to Jmol.
403    // ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
404    // fileName, null, reader, false, null, null, 0);
405  0 jmolViewer.openStringInline(string);
406    }
407   
 
408  1 toggle protected void mouseOverStructure(int atomIndex, final String strInfo)
409    {
410  1 int pdbResNum;
411  1 int alocsep = strInfo.indexOf("^");
412  1 int mdlSep = strInfo.indexOf("/");
413  1 int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
414   
415  1 if (chainSeparator == -1)
416    {
417  0 chainSeparator = strInfo.indexOf(".");
418  0 if (mdlSep > -1 && mdlSep < chainSeparator)
419    {
420  0 chainSeparator1 = chainSeparator;
421  0 chainSeparator = mdlSep;
422    }
423    }
424    // handle insertion codes
425  1 if (alocsep != -1)
426    {
427  0 pdbResNum = Integer.parseInt(
428    strInfo.substring(strInfo.indexOf("]") + 1, alocsep));
429   
430    }
431    else
432    {
433  1 pdbResNum = Integer.parseInt(
434    strInfo.substring(strInfo.indexOf("]") + 1, chainSeparator));
435    }
436  1 String chainId;
437   
438  1 if (strInfo.indexOf(":") > -1)
439    {
440  1 chainId = strInfo.substring(strInfo.indexOf(":") + 1,
441    strInfo.indexOf("."));
442    }
443    else
444    {
445  0 chainId = " ";
446    }
447   
448  1 String pdbfilename = modelFileNames[0]; // default is first model
449  1 if (mdlSep > -1)
450    {
451  1 if (chainSeparator1 == -1)
452    {
453  1 chainSeparator1 = strInfo.indexOf(".", mdlSep);
454    }
455  1 String mdlId = (chainSeparator1 > -1)
456    ? strInfo.substring(mdlSep + 1, chainSeparator1)
457    : strInfo.substring(mdlSep + 1);
458  1 try
459    {
460    // recover PDB filename for the model hovered over.
461  1 int mnumber = Integer.valueOf(mdlId).intValue() - 1;
462  1 if (_modelFileNameMap != null)
463    {
464  0 int _mp = _modelFileNameMap.length - 1;
465   
466  0 while (mnumber < _modelFileNameMap[_mp])
467    {
468  0 _mp--;
469    }
470  0 pdbfilename = modelFileNames[_mp];
471    }
472    else
473    {
474  1 if (mnumber >= 0 && mnumber < modelFileNames.length)
475    {
476  1 pdbfilename = modelFileNames[mnumber];
477    }
478   
479  1 if (pdbfilename == null)
480    {
481  0 pdbfilename = new File(jmolViewer.ms.getModelFileName(mnumber))
482    .getAbsolutePath();
483    }
484    }
485    } catch (Exception e)
486    {
487    }
488    }
489   
490    /*
491    * highlight position on alignment(s); if some text is returned, show this as a
492    * second line on the structure hover tooltip
493    */
494  1 String label = getSsm().mouseOverStructure(pdbResNum, chainId,
495    pdbfilename);
496  1 if (label != null)
497    {
498    // change comma to pipe separator (newline token for Jmol)
499  0 label = label.replace(',', '|');
500  0 StringTokenizer toks = new StringTokenizer(strInfo, " ");
501  0 StringBuilder sb = new StringBuilder();
502  0 sb.append("select ").append(String.valueOf(pdbResNum)).append(":")
503    .append(chainId).append("/1");
504  0 sb.append(";set hoverLabel \"").append(toks.nextToken()).append(" ")
505    .append(toks.nextToken());
506  0 sb.append("|").append(label).append("\"");
507  0 executeCommand(new StructureCommand(sb.toString()), false);
508    }
509    }
510   
 
511  0 toggle public void notifyAtomHovered(int atomIndex, String strInfo, String data)
512    {
513  0 if (strInfo.equals(lastMessage))
514    {
515  0 return;
516    }
517  0 lastMessage = strInfo;
518  0 if (data != null)
519    {
520  0 jalview.bin.Console.errPrintln(
521    "Ignoring additional hover info: " + data + " (other info: '"
522    + strInfo + "' pos " + atomIndex + ")");
523    }
524  0 mouseOverStructure(atomIndex, strInfo);
525    }
526   
527    /*
528    * { if (history != null && strStatus != null &&
529    * !strStatus.equals("Script completed")) { history.append("\n" + strStatus); }
530    * }
531    */
532   
 
533  0 toggle public void notifyAtomPicked(int atomIndex, String strInfo,
534    String strData)
535    {
536    /**
537    * this implements the toggle label behaviour copied from the original
538    * structure viewer, mc_view
539    */
540  0 if (strData != null)
541    {
542  0 jalview.bin.Console.errPrintln(
543    "Ignoring additional pick data string " + strData);
544    }
545  0 int chainSeparator = strInfo.indexOf(":");
546  0 int p = 0;
547  0 if (chainSeparator == -1)
548    {
549  0 chainSeparator = strInfo.indexOf(".");
550    }
551   
552  0 String picked = strInfo.substring(strInfo.indexOf("]") + 1,
553    chainSeparator);
554  0 String mdlString = "";
555  0 if ((p = strInfo.indexOf(":")) > -1)
556    {
557  0 picked += strInfo.substring(p, strInfo.indexOf("."));
558    }
559   
560  0 if ((p = strInfo.indexOf("/")) > -1)
561    {
562  0 mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
563    }
564  0 picked = "((" + picked + ".CA" + mdlString + ")|(" + picked + ".P"
565    + mdlString + "))";
566  0 jmolHistory(false);
567   
568  0 if (!atomsPicked.contains(picked))
569    {
570  0 jmolScript("select " + picked + ";label %n %r:%c");
571  0 atomsPicked.addElement(picked);
572    }
573    else
574    {
575  0 jmolViewer.evalString("select " + picked + ";label off");
576  0 atomsPicked.removeElement(picked);
577    }
578  0 jmolHistory(true);
579    // TODO: in application this happens
580    //
581    // if (scriptWindow != null)
582    // {
583    // scriptWindow.sendConsoleMessage(strInfo);
584    // scriptWindow.sendConsoleMessage("\n");
585    // }
586   
587    }
588   
 
589  233 toggle @Override
590    public void notifyCallback(CBK type, Object[] data)
591    {
592    /*
593    * ensure processed in AWT thread to avoid risk of deadlocks
594    */
595  233 SwingUtilities.invokeLater(new Runnable()
596    {
597   
 
598  233 toggle @Override
599    public void run()
600    {
601  233 processCallback(type, data);
602    }
603    });
604    }
605   
606    /**
607    * Processes one callback notification from Jmol
608    *
609    * @param type
610    * @param data
611    */
 
612  233 toggle protected void processCallback(CBK type, Object[] data)
613    {
614  233 try
615    {
616  233 switch (type)
617    {
618  73 case LOADSTRUCT:
619  73 notifyFileLoaded((String) data[1], (String) data[2],
620    (String) data[3], (String) data[4],
621    ((Integer) data[5]).intValue());
622   
623  73 break;
624  0 case PICK:
625  0 notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1],
626    (String) data[0]);
627    // also highlight in alignment
628    // deliberate fall through
629  0 case HOVER:
630  0 notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1],
631    (String) data[0]);
632  0 break;
633  12 case SCRIPT:
634  12 notifyScriptTermination((String) data[2],
635    ((Integer) data[3]).intValue());
636  12 break;
637  47 case ECHO:
638  47 sendConsoleEcho((String) data[1]);
639  47 break;
640  0 case MESSAGE:
641  0 sendConsoleMessage(
642  0 (data == null) ? ((String) null) : (String) data[1]);
643  0 break;
644  0 case ERROR:
645    // jalview.bin.Console.errPrintln("Ignoring error callback.");
646  0 break;
647  91 case SYNC:
648  0 case RESIZE:
649  91 refreshGUI();
650  91 break;
651  10 case MEASURE:
652   
653  0 case CLICK:
654  0 default:
655  10 jalview.bin.Console.errPrintln(
656    "Unhandled callback " + type + " " + data[1].toString());
657  10 break;
658    }
659    } catch (Exception e)
660    {
661  0 jalview.bin.Console
662    .errPrintln("Squashed Jmol callback handler error:");
663  0 e.printStackTrace();
664    }
665    }
666   
 
667  464 toggle @Override
668    public boolean notifyEnabled(CBK callbackPick)
669    {
670  464 switch (callbackPick)
671    {
672  47 case ECHO:
673  73 case LOADSTRUCT:
674  10 case MEASURE:
675  0 case MESSAGE:
676  0 case PICK:
677  12 case SCRIPT:
678  0 case HOVER:
679  0 case ERROR:
680  142 return true;
681  322 default:
682  322 return false;
683    }
684    }
685   
686    // incremented every time a load notification is successfully handled -
687    // lightweight mechanism for other threads to detect when they can start
688    // referrring to new structures.
689    private long loadNotifiesHandled = 0;
690   
 
691  100 toggle public long getLoadNotifiesHandled()
692    {
693  100 return loadNotifiesHandled;
694    }
695   
 
696  73 toggle public void notifyFileLoaded(String fullPathName, String fileName2,
697    String modelName, String errorMsg, int modelParts)
698    {
699  73 if (errorMsg != null)
700    {
701  10 fileLoadingError = errorMsg;
702  10 refreshGUI();
703  10 return;
704    }
705    // TODO: deal sensibly with models loaded inLine:
706    // modelName will be null, as will fullPathName.
707   
708    // the rest of this routine ignores the arguments, and simply interrogates
709    // the Jmol view to find out what structures it contains, and adds them to
710    // the structure selection manager.
711  63 fileLoadingError = null;
712  63 String[] oldmodels = modelFileNames;
713  63 modelFileNames = null;
714  63 boolean notifyLoaded = false;
715  63 String[] modelfilenames = getStructureFiles();
716  63 if (modelfilenames == null)
717    {
718    // Jmol is still loading files!
719  0 return;
720    }
721  63 if (jalview.bin.Console.isTraceEnabled())
722    {
723  0 jalview.bin.Console.trace("New structures loaded in Jmol:");
724  0 int i=1;
725  0 for (String mfn: modelfilenames)
726    {
727  0 jalview.bin.Console.trace(i++ +" "+((mfn==null) ? "NULL" : mfn));
728    }
729    }
730    // first check if we've lost any structures
731  63 if (oldmodels != null && oldmodels.length > 0)
732    {
733  48 int oldm = 0;
734  105 for (int i = 0; i < oldmodels.length; i++)
735    {
736  70 for (int n = 0; n < modelfilenames.length; n++)
737    {
738  70 if (modelfilenames[n] == oldmodels[i])
739    {
740  57 oldmodels[i] = null;
741  57 break;
742    }
743    }
744  57 if (oldmodels[i] != null)
745    {
746  0 oldm++;
747    }
748    }
749  48 if (oldm > 0)
750    {
751  0 String[] oldmfn = new String[oldm];
752  0 oldm = 0;
753  0 for (int i = 0; i < oldmodels.length; i++)
754    {
755  0 if (oldmodels[i] != null)
756    {
757  0 oldmfn[oldm++] = oldmodels[i];
758    }
759    }
760    // deregister the Jmol instance for these structures - we'll add
761    // ourselves again at the end for the current structure set.
762  0 getSsm().removeStructureViewerListener(this, oldmfn);
763    }
764    }
765  63 refreshPdbEntries();
766  142 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
767    {
768  79 String fileName = modelfilenames[modelnum];
769  79 boolean foundEntry = false;
770  79 StructureFile pdb = null;
771  79 String pdbfile = null;
772    // model was probably loaded inline - so check the pdb file hashcode
773  79 if (loadedInline)
774    {
775    // calculate essential attributes for the pdb data imported inline.
776    // prolly need to resolve modelnumber properly - for now just use our
777    // 'best guess'
778  0 pdbfile = jmolViewer.getData(
779    "" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
780    }
781    // search pdbentries and sequences to find correct pdbentry for this
782    // model
783  202 for (int pe = 0; pe < getPdbCount(); pe++)
784    {
785  123 boolean matches = false;
786  123 addSequence(pe, getSequence()[pe]);
787  123 if (fileName == null)
788    {
789  0 if (false)
790    // see JAL-623 - need method of matching pasted data up
791    {
792    // ALSO need to use the PDBEntry based setMapping method to pass in other metadata
793  0 pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
794    pdbfile, DataSourceType.PASTE, getIProgressIndicator());
795  0 getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
796  0 matches = true;
797  0 foundEntry = true;
798    }
799    }
800    else
801    {
802  123 PDBEntry ppe = getPdbEntry(pe);
803  123 if (ppe == null)
804    {
805  0 Console.warn(
806    "Please report under JAL-4440: Unexpected null entry for PDBEntry for a structure (for structure "
807    + fileName + ")");
808   
809  0 continue;
810    }
811  123 if (ppe.getFile() == null)
812    {
813  0 Console.warn(
814    "Please report under JAL-4440: Unexpected null entry for file that we just tried to load into Jmol: pdbEntry: "
815    + ppe.toString() + "(for structure " + fileName
816    + ")");
817  0 continue;
818    }
819  123 String jvPdbFile = getPdbEntry(pe).getFile();
820  123 File fl = new File(jvPdbFile);
821  123 matches = fl.equals(new File(fileName)) || JmolCommands.filePathMatch(fileName, jvPdbFile);
822  123 if (matches)
823    {
824  76 foundEntry = true;
825    // TODO: Jmol can in principle retrieve from CLASSLOADER but
826    // this
827    // needs
828    // to be tested. See mantis bug
829    // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
830  76 DataSourceType protocol = DataSourceType.URL;
831  76 try
832    {
833  76 if (fl.exists())
834    {
835  73 protocol = DataSourceType.FILE;
836    }
837    } catch (Exception e)
838    {
839    } catch (Error e)
840    {
841    }
842    // Explicitly map to the filename used by Jmol ;
843  76 pdb = getSsm().setMapping(true,getSequence()[pe], getPdbEntry(pe), getChains()[pe],
844    getIProgressIndicator());
845    // pdbentry[pe].getFile(), protocol);
846   
847    }
848    }
849  123 if (matches)
850    {
851  76 stashFoundChains(pdb, fileName);
852  76 notifyLoaded = true;
853    }
854    }
855   
856  79 if (!foundEntry && associateNewStructs)
857    {
858    // this is a foreign pdb file that jalview doesn't know about - add
859    // it to the dataset and try to find a home - either on a matching
860    // sequence or as a new sequence.
861  0 String pdbcontent = jmolViewer.getData("/" + (modelnum + 1) + ".1",
862    "PDB");
863    // parse pdb file into a chain, etc.
864    // locate best match for pdb in associated views and add mapping to
865    // ssm
866    // if properly registered then
867  0 notifyLoaded = true;
868   
869    }
870    }
871    // FILE LOADED OK
872    // so finally, update the jmol bits and pieces
873    // if (jmolpopup != null)
874    // {
875    // // potential for deadlock here:
876    // // jmolpopup.updateComputedMenus();
877    // }
878  63 if (!isLoadingFromArchive())
879    {
880  56 jmolScript(
881    "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
882    }
883    // register ourselves as a listener and notify the gui that it needs to
884    // update itself.
885  63 getSsm().addStructureViewerListener(this);
886  63 if (notifyLoaded)
887    {
888  60 FeatureRenderer fr = getFeatureRenderer(null);
889  60 if (fr != null)
890    {
891  52 FeatureSettingsModelI colours = new Pdb().getFeatureColourScheme();
892  52 ((AppJmol) getViewer()).getAlignmentPanel().av
893    .applyFeaturesStyle(colours);
894    }
895  60 refreshGUI();
896  60 loadNotifiesHandled++;
897    }
898  63 setLoadingFromArchive(false);
899    }
900   
901   
 
902  76 toggle protected IProgressIndicator getIProgressIndicator()
903    {
904  76 return null;
905    }
906   
 
907  0 toggle public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
908    {
909  0 notifyAtomPicked(iatom, strMeasure, null);
910    }
911   
912    public abstract void notifyScriptTermination(String strStatus,
913    int msWalltime);
914   
915    /**
916    * display a message echoed from the jmol viewer
917    *
918    * @param strEcho
919    */
920    public abstract void sendConsoleEcho(String strEcho); /*
921    * { showConsole(true);
922    *
923    * history.append("\n" + strEcho); }
924    */
925   
926    // /End JmolStatusListener
927    // /////////////////////////////
928   
929    /**
930    * @param strStatus
931    * status message - usually the response received after a script
932    * executed
933    */
934    public abstract void sendConsoleMessage(String strStatus);
935   
 
936  0 toggle @Override
937    public void setCallbackFunction(String callbackType,
938    String callbackFunction)
939    {
940  0 jalview.bin.Console
941    .errPrintln("Ignoring set-callback request to associate "
942    + callbackType + " with function " + callbackFunction);
943   
944    }
945   
946   
 
947  0 toggle public void showHelp()
948    {
949  0 showUrl("http://wiki.jmol.org"
950    // BH 2018 "http://jmol.sourceforge.net/docs/JmolUserGuide/"
951    , "jmolHelp");
952    }
953   
954    /**
955    * open the URL somehow
956    *
957    * @param target
958    */
959    public abstract void showUrl(String url, String target);
960   
961    /**
962    * called to show or hide the associated console window container.
963    *
964    * @param show
965    */
966    public abstract void showConsole(boolean show);
967   
 
968  210 toggle public static Viewer getJmolData(JmolParser jmolParser)
969    {
970  210 return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null,
971    "-x -o -n", jmolParser);
972    }
973   
974    /**
975    *
976    *
977    *
978    * @param renderPanel
979    * @param jmolfileio
980    * - when true will initialise jmol's file IO system (should be false
981    * in applet context)
982    * @param htmlName
983    * @param documentBase
984    * @param codeBase
985    * @param commandOptions
986    */
 
987  0 toggle public void allocateViewer(Container renderPanel, boolean jmolfileio,
988    String htmlName, URL documentBase, URL codeBase,
989    String commandOptions)
990    {
991  0 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
992    codeBase, commandOptions, null, null);
993    }
994   
995    /**
996    *
997    * @param renderPanel
998    * @param jmolfileio
999    * - when true will initialise jmol's file IO system (should be false
1000    * in applet context)
1001    * @param htmlName
1002    * @param documentBase
1003    * @param codeBase
1004    * @param commandOptions
1005    * @param consolePanel
1006    * - panel to contain Jmol console
1007    * @param buttonsToShow
1008    * - buttons to show on the console, in order
1009    */
 
1010  48 toggle public void allocateViewer(Container renderPanel, boolean jmolfileio,
1011    String htmlName, URL documentBase, URL codeBase,
1012    String commandOptions, final Container consolePanel,
1013    String buttonsToShow)
1014    {
1015   
1016  48 jalview.bin.Console
1017    .errPrintln("Allocating Jmol Viewer: " + commandOptions);
1018   
1019  48 if (commandOptions == null)
1020    {
1021  0 commandOptions = "";
1022    }
1023  48 jmolViewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1024  48 (jmolfileio ? new SmarterJmolAdapter() : null),
1025    htmlName + ((Object) this).toString(), documentBase, codeBase,
1026    commandOptions, this);
1027   
1028  48 jmolViewer.setJmolStatusListener(this); // extends JmolCallbackListener
1029   
1030  48 try
1031    {
1032  48 console = createJmolConsole(consolePanel, buttonsToShow);
1033    } catch (Throwable e)
1034    {
1035  1 jalview.bin.Console
1036    .errPrintln("Could not create Jmol application console. "
1037    + e.getMessage());
1038  1 e.printStackTrace();
1039    }
1040  48 if (consolePanel != null)
1041    {
1042  48 consolePanel.addComponentListener(this);
1043   
1044    }
1045   
1046    }
1047   
1048    protected abstract JmolAppConsoleInterface createJmolConsole(
1049    Container consolePanel, String buttonsToShow);
1050   
1051    // BH 2018 -- Jmol console is not working due to problems with styled
1052    // documents.
1053   
1054    protected org.jmol.api.JmolAppConsoleInterface console = null;
1055   
 
1056  0 toggle @Override
1057    public int[] resizeInnerPanel(String data)
1058    {
1059    // Jalview doesn't honour resize panel requests
1060  0 return null;
1061    }
1062   
1063    /**
1064    *
1065    */
 
1066  46 toggle protected void closeConsole()
1067    {
1068  46 if (console != null)
1069    {
1070  45 try
1071    {
1072  45 console.setVisible(false);
1073    } catch (Error e)
1074    {
1075    } catch (Exception x)
1076    {
1077    }
1078  45 ;
1079  45 console = null;
1080    }
1081    }
1082   
1083    /**
1084    * ComponentListener method
1085    */
 
1086  0 toggle @Override
1087    public void componentMoved(ComponentEvent e)
1088    {
1089    }
1090   
1091    /**
1092    * ComponentListener method
1093    */
 
1094  0 toggle @Override
1095    public void componentResized(ComponentEvent e)
1096    {
1097    }
1098   
1099    /**
1100    * ComponentListener method
1101    */
 
1102  0 toggle @Override
1103    public void componentShown(ComponentEvent e)
1104    {
1105  0 showConsole(true);
1106    }
1107   
1108    /**
1109    * ComponentListener method
1110    */
 
1111  0 toggle @Override
1112    public void componentHidden(ComponentEvent e)
1113    {
1114  0 showConsole(false);
1115    }
1116   
1117   
 
1118  368 toggle @Override
1119    protected String getModelIdForFile(String pdbFile)
1120    {
1121  368 if (modelFileNames == null)
1122    {
1123  0 return "";
1124    }
1125  522 for (int i = 0; i < modelFileNames.length; i++)
1126    {
1127  520 if (JmolCommands.filePathMatch(modelFileNames[i],pdbFile))
1128    {
1129  366 return String.valueOf(i + 1);
1130    }
1131    }
1132  2 return "";
1133    }
1134   
 
1135  3 toggle @Override
1136    protected ViewerType getViewerType()
1137    {
1138  3 return ViewerType.JMOL;
1139    }
1140   
 
1141  0 toggle @Override
1142    protected String getModelId(int pdbfnum, String file)
1143    {
1144  0 return String.valueOf(pdbfnum + 1);
1145    }
1146   
1147    /**
1148    * Returns ".spt" - the Jmol session file extension
1149    *
1150    * @return
1151    * @see https://chemapps.stolaf.edu/jmol/docs/#writemodel
1152    */
 
1153  3 toggle @Override
1154    public String getSessionFileExtension()
1155    {
1156  3 return ".spt";
1157    }
1158   
 
1159  0 toggle @Override
1160    public void selectionChanged(BS arg0)
1161    {
1162    // TODO Auto-generated method stub
1163   
1164    }
1165   
 
1166  0 toggle @Override
1167    public SequenceRenderer getSequenceRenderer(AlignmentViewPanel avp)
1168    {
1169  0 return new jalview.gui.SequenceRenderer(avp.getAlignViewport());
1170    }
1171   
 
1172  0 toggle @Override
1173    public String getHelpURL()
1174    {
1175  0 return "http://wiki.jmol.org"; // BH 2018
1176    }
1177    }