Clover icon

Coverage Report

  1. Project Clover database Mon Dec 8 2025 13:36:16 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,157
789
152
0.49
6.35
49
3.1

Classes

Class Line # Actions
JalviewJmolBinding 66 311 152
0.546184754.6%
 

Contributing tests

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