Clover icon

Coverage Report

  1. Project Clover database Fri Jan 16 2026 12:43:44 GMT
  2. Package jalview.ext.jmol

File JalviewJmolBinding.java

 

Coverage histogram

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

Code metrics

138
311
49
1
1,160
789
152
0.49
6.35
49
3.1

Classes

Class Line # Actions
JalviewJmolBinding 64 311 152
0.544176754.4%
 

Contributing tests

This file is covered by 59 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  50 toggle public JalviewJmolBinding(StructureSelectionManager ssm,
88    PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
89    DataSourceType protocol)
90    {
91  50 super(ssm, pdbentry, sequenceIs, protocol);
92  50 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  50 toggle public String getViewerTitle()
120    {
121  50 return getDynamicViewerTitle("Jmol", true);
122    }
123   
 
124  58 toggle private String jmolScript(String script)
125    {
126  58 return jmolScript(script, false);
127    }
128   
 
129  1163 toggle private String jmolScript(String script, boolean useScriptWait)
130    {
131  1163 Console.debug(">>Jmol>> " + script);
132  1163 String s;
133  1163 if (useScriptWait)
134    {
135  3 s = jmolViewer.scriptWait(script);
136    }
137    else
138    {
139  1160 s = jmolViewer.evalStringQuiet(script); // scriptWait(script); BH
140    }
141  1162 Console.debug("<<Jmol<< " + s);
142   
143  1162 return s;
144    }
145   
 
146  436 toggle @Override
147    public List<String> executeCommand(StructureCommandI command,
148    boolean getReply)
149    {
150  436 if (command == null || jmolViewer==null)
151    {
152  5 return null;
153    }
154   
155  431 String cmd = command.getCommand();
156  431 if (cmd==null) {
157  0 return null;
158    }
159  431 jmolHistory(false);
160  430 if (lastCommand == null || !lastCommand.equals(cmd))
161    {
162  244 jmolScript(cmd + "\n", command.isWaitNeeded());
163    }
164  430 jmolHistory(true);
165  430 lastCommand = cmd;
166  430 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  165 for (int mc = 0; mc < jmolViewer.ms.mc; mc++)
202    {
203  97 Map<String, String> hets = jmolViewer.ms.getHeteroList(mc);
204  97 if (hets != null)
205    {
206  13 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  1199 toggle @Override
237    public synchronized String[] getStructureFiles()
238    {
239  1199 if (jmolViewer == null)
240    {
241  46 return new String[0];
242    }
243   
244  1153 if (modelFileNames == null)
245    {
246  262 int modelCount = jmolViewer.ms.mc;
247  262 String filePath = null;
248  262 List<String> mset = new ArrayList<>();
249  550 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  288 filePath = jmolViewer.ms.getModelFileName(i);
256  288 if (filePath != null && !mset.contains(filePath))
257    {
258  122 mset.add(filePath);
259    }
260    }
261  262 if (!mset.isEmpty())
262    {
263  96 modelFileNames = mset.toArray(new String[mset.size()]);
264    }
265    }
266   
267  1153 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  861 toggle private void jmolHistory(boolean enable)
384    {
385  861 jmolHistory(enable, false);
386    }
387   
 
388  861 toggle private void jmolHistory(boolean enable, boolean useScriptWait)
389    {
390  861 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  246 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  246 SwingUtilities.invokeLater(new Runnable()
596    {
597   
 
598  246 toggle @Override
599    public void run()
600    {
601  246 processCallback(type, data);
602    }
603    });
604    }
605   
606    /**
607    * Processes one callback notification from Jmol
608    *
609    * @param type
610    * @param data
611    */
 
612  246 toggle protected void processCallback(CBK type, Object[] data)
613    {
614  246 try
615    {
616  246 switch (type)
617    {
618  79 case LOADSTRUCT:
619  79 notifyFileLoaded((String) data[1], (String) data[2],
620    (String) data[3], (String) data[4],
621    ((Integer) data[5]).intValue());
622   
623  79 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  96 case SYNC:
648  0 case RESIZE:
649  96 refreshGUI();
650  96 break;
651  12 case MEASURE:
652   
653  0 case CLICK:
654  0 default:
655  12 jalview.bin.Console.errPrintln(
656    "Unhandled callback " + type + " " + data[1].toString());
657  12 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  466 toggle @Override
668    public boolean notifyEnabled(CBK callbackPick)
669    {
670  466 switch (callbackPick)
671    {
672  47 case ECHO:
673  79 case LOADSTRUCT:
674  12 case MEASURE:
675  0 case MESSAGE:
676  0 case PICK:
677  12 case SCRIPT:
678  0 case HOVER:
679  0 case ERROR:
680  150 return true;
681  316 default:
682  316 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  104 toggle public long getLoadNotifiesHandled()
692    {
693  104 return loadNotifiesHandled;
694    }
695   
 
696  79 toggle public void notifyFileLoaded(String fullPathName, String fileName2,
697    String modelName, String errorMsg, int modelParts)
698    {
699  79 if (errorMsg != null)
700    {
701  12 fileLoadingError = errorMsg;
702  12 refreshGUI();
703  12 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  67 fileLoadingError = null;
712  67 String[] oldmodels = modelFileNames;
713  67 modelFileNames = null;
714  67 boolean notifyLoaded = false;
715  67 String[] modelfilenames = getStructureFiles();
716  67 if (modelfilenames == null)
717    {
718    // Jmol is still loading files!
719  3 return;
720    }
721  64 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  64 if (oldmodels != null && oldmodels.length > 0)
732    {
733  46 int oldm = 0;
734  103 for (int i = 0; i < oldmodels.length; i++)
735    {
736  73 for (int n = 0; n < modelfilenames.length; n++)
737    {
738  73 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  46 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  64 refreshPdbEntries();
766  144 for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
767    {
768  80 String fileName = modelfilenames[modelnum];
769  80 boolean foundEntry = false;
770  80 StructureFile pdb = null;
771  80 String pdbfile = null;
772    // model was probably loaded inline - so check the pdb file hashcode
773  80 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  204 for (int pe = 0; pe < getPdbCount(); pe++)
784    {
785  124 boolean matches = false;
786  124 addSequence(pe, getSequence()[pe]);
787  124 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  124 String jvPdbFile = getPdbEntry(pe).getFile();
803  124 File fl = new File(jvPdbFile);
804  124 matches = fl.equals(new File(fileName)) || JmolCommands.filePathMatch(fileName, jvPdbFile);
805  124 if (matches)
806    {
807  77 foundEntry = true;
808    // TODO: Jmol can in principle retrieve from CLASSLOADER but
809    // this
810    // needs
811    // to be tested. See mantis bug
812    // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
813  77 DataSourceType protocol = DataSourceType.URL;
814  77 try
815    {
816  77 if (fl.exists())
817    {
818  74 protocol = DataSourceType.FILE;
819    }
820    } catch (Exception e)
821    {
822    } catch (Error e)
823    {
824    }
825    // Explicitly map to the filename used by Jmol ;
826  77 pdb = getSsm().setMapping(true,getSequence()[pe], getPdbEntry(pe), getChains()[pe],
827    getIProgressIndicator());
828    // pdbentry[pe].getFile(), protocol);
829   
830    }
831    }
832  124 if (matches)
833    {
834  77 stashFoundChains(pdb, fileName);
835  77 notifyLoaded = true;
836    }
837    }
838   
839  80 if (!foundEntry && associateNewStructs)
840    {
841    // this is a foreign pdb file that jalview doesn't know about - add
842    // it to the dataset and try to find a home - either on a matching
843    // sequence or as a new sequence.
844  0 String pdbcontent = jmolViewer.getData("/" + (modelnum + 1) + ".1",
845    "PDB");
846    // parse pdb file into a chain, etc.
847    // locate best match for pdb in associated views and add mapping to
848    // ssm
849    // if properly registered then
850  0 notifyLoaded = true;
851   
852    }
853    }
854    // FILE LOADED OK
855    // so finally, update the jmol bits and pieces
856    // if (jmolpopup != null)
857    // {
858    // // potential for deadlock here:
859    // // jmolpopup.updateComputedMenus();
860    // }
861  64 if (!isLoadingFromArchive())
862    {
863  58 jmolScript(
864    "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
865    }
866    // register ourselves as a listener and notify the gui that it needs to
867    // update itself.
868  64 getSsm().addStructureViewerListener(this);
869  64 if (notifyLoaded)
870    {
871  61 FeatureRenderer fr = getFeatureRenderer(null);
872  61 if (fr != null)
873    {
874  49 FeatureSettingsModelI colours = new Pdb().getFeatureColourScheme();
875  49 ((AppJmol) getViewer()).getAlignmentPanel().av
876    .applyFeaturesStyle(colours);
877    }
878  61 refreshGUI();
879  61 loadNotifiesHandled++;
880    }
881  64 setLoadingFromArchive(false);
882    }
883   
884   
 
885  77 toggle protected IProgressIndicator getIProgressIndicator()
886    {
887  77 return null;
888    }
889   
 
890  0 toggle public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
891    {
892  0 notifyAtomPicked(iatom, strMeasure, null);
893    }
894   
895    public abstract void notifyScriptTermination(String strStatus,
896    int msWalltime);
897   
898    /**
899    * display a message echoed from the jmol viewer
900    *
901    * @param strEcho
902    */
903    public abstract void sendConsoleEcho(String strEcho); /*
904    * { showConsole(true);
905    *
906    * history.append("\n" + strEcho); }
907    */
908   
909    // /End JmolStatusListener
910    // /////////////////////////////
911   
912    /**
913    * @param strStatus
914    * status message - usually the response received after a script
915    * executed
916    */
917    public abstract void sendConsoleMessage(String strStatus);
918   
 
919  0 toggle @Override
920    public void setCallbackFunction(String callbackType,
921    String callbackFunction)
922    {
923  0 jalview.bin.Console
924    .errPrintln("Ignoring set-callback request to associate "
925    + callbackType + " with function " + callbackFunction);
926   
927    }
928   
929   
 
930  0 toggle public void showHelp()
931    {
932  0 showUrl("http://wiki.jmol.org"
933    // BH 2018 "http://jmol.sourceforge.net/docs/JmolUserGuide/"
934    , "jmolHelp");
935    }
936   
937    /**
938    * open the URL somehow
939    *
940    * @param target
941    */
942    public abstract void showUrl(String url, String target);
943   
944    /**
945    * called to show or hide the associated console window container.
946    *
947    * @param show
948    */
949    public abstract void showConsole(boolean show);
950   
 
951  211 toggle public static Viewer getJmolData(JmolParser jmolParser)
952    {
953  211 return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null,
954    "-x -o -n", jmolParser);
955    }
956   
957    /**
958    *
959    *
960    *
961    * @param renderPanel
962    * @param jmolfileio
963    * - when true will initialise jmol's file IO system (should be false
964    * in applet context)
965    * @param htmlName
966    * @param documentBase
967    * @param codeBase
968    * @param commandOptions
969    */
 
970  0 toggle public void allocateViewer(Container renderPanel, boolean jmolfileio,
971    String htmlName, URL documentBase, URL codeBase,
972    String commandOptions)
973    {
974  0 allocateViewer(renderPanel, jmolfileio, htmlName, documentBase,
975    codeBase, commandOptions, null, null);
976    }
977   
978    /**
979    *
980    * @param renderPanel
981    * @param jmolfileio
982    * - when true will initialise jmol's file IO system (should be false
983    * in applet context)
984    * @param htmlName
985    * @param documentBase
986    * @param codeBase
987    * @param commandOptions
988    * @param consolePanel
989    * - panel to contain Jmol console
990    * @param buttonsToShow
991    * - buttons to show on the console, in order
992    */
 
993  50 toggle public void allocateViewer(Container renderPanel, boolean jmolfileio,
994    String htmlName, URL documentBase, URL codeBase,
995    String commandOptions, final Container consolePanel,
996    String buttonsToShow)
997    {
998   
999  50 jalview.bin.Console
1000    .errPrintln("Allocating Jmol Viewer: " + commandOptions);
1001   
1002  50 if (commandOptions == null)
1003    {
1004  0 commandOptions = "";
1005    }
1006  50 jmolViewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
1007  50 (jmolfileio ? new SmarterJmolAdapter() : null),
1008    htmlName + ((Object) this).toString(), documentBase, codeBase,
1009    commandOptions, this);
1010   
1011  50 jmolViewer.setJmolStatusListener(this); // extends JmolCallbackListener
1012   
1013  50 try
1014    {
1015  50 console = createJmolConsole(consolePanel, buttonsToShow);
1016    } catch (Throwable e)
1017    {
1018  0 jalview.bin.Console
1019    .errPrintln("Could not create Jmol application console. "
1020    + e.getMessage());
1021  0 e.printStackTrace();
1022    }
1023  50 if (consolePanel != null)
1024    {
1025  50 consolePanel.addComponentListener(this);
1026   
1027    }
1028   
1029    }
1030   
1031    protected abstract JmolAppConsoleInterface createJmolConsole(
1032    Container consolePanel, String buttonsToShow);
1033   
1034    // BH 2018 -- Jmol console is not working due to problems with styled
1035    // documents.
1036   
1037    protected org.jmol.api.JmolAppConsoleInterface console = null;
1038   
 
1039  0 toggle @Override
1040    public int[] resizeInnerPanel(String data)
1041    {
1042    // Jalview doesn't honour resize panel requests
1043  0 return null;
1044    }
1045   
1046    /**
1047    *
1048    */
 
1049  48 toggle protected void closeConsole()
1050    {
1051  48 if (console != null)
1052    {
1053  46 try
1054    {
1055  46 console.setVisible(false);
1056    } catch (Error e)
1057    {
1058    } catch (Exception x)
1059    {
1060    }
1061  46 ;
1062  46 console = null;
1063    }
1064    }
1065   
1066    /**
1067    * ComponentListener method
1068    */
 
1069  0 toggle @Override
1070    public void componentMoved(ComponentEvent e)
1071    {
1072    }
1073   
1074    /**
1075    * ComponentListener method
1076    */
 
1077  0 toggle @Override
1078    public void componentResized(ComponentEvent e)
1079    {
1080    }
1081   
1082    /**
1083    * ComponentListener method
1084    */
 
1085  0 toggle @Override
1086    public void componentShown(ComponentEvent e)
1087    {
1088  0 showConsole(true);
1089    }
1090   
1091    /**
1092    * ComponentListener method
1093    */
 
1094  0 toggle @Override
1095    public void componentHidden(ComponentEvent e)
1096    {
1097  0 showConsole(false);
1098    }
1099   
1100   
 
1101  388 toggle @Override
1102    protected String getModelIdForFile(String pdbFile)
1103    {
1104  388 if (modelFileNames == null)
1105    {
1106  0 return "";
1107    }
1108  550 for (int i = 0; i < modelFileNames.length; i++)
1109    {
1110  550 if (JmolCommands.filePathMatch(modelFileNames[i],pdbFile))
1111    {
1112  388 return String.valueOf(i + 1);
1113    }
1114    }
1115  0 return "";
1116    }
1117   
 
1118  3 toggle @Override
1119    protected ViewerType getViewerType()
1120    {
1121  3 return ViewerType.JMOL;
1122    }
1123   
 
1124  0 toggle @Override
1125    protected String getModelId(int pdbfnum, String file)
1126    {
1127  0 return String.valueOf(pdbfnum + 1);
1128    }
1129   
1130    /**
1131    * Returns ".spt" - the Jmol session file extension
1132    *
1133    * @return
1134    * @see https://chemapps.stolaf.edu/jmol/docs/#writemodel
1135    */
 
1136  3 toggle @Override
1137    public String getSessionFileExtension()
1138    {
1139  3 return ".spt";
1140    }
1141   
 
1142  0 toggle @Override
1143    public void selectionChanged(BS arg0)
1144    {
1145    // TODO Auto-generated method stub
1146   
1147    }
1148   
 
1149  0 toggle @Override
1150    public SequenceRenderer getSequenceRenderer(AlignmentViewPanel avp)
1151    {
1152  0 return new jalview.gui.SequenceRenderer(avp.getAlignViewport());
1153    }
1154   
 
1155  0 toggle @Override
1156    public String getHelpURL()
1157    {
1158  0 return "http://wiki.jmol.org"; // BH 2018
1159    }
1160    }