JAL-3626 use Viewer.scriptWait() to send Jmol commands (Bob Hanson)
[jalview.git] / src / jalview / ext / jmol / JalviewJmolBinding.java
index 844fb1b..038ca48 100644 (file)
  */
 package jalview.ext.jmol;
 
-import jalview.api.FeatureRenderer;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceI;
-import jalview.gui.IProgressIndicator;
-import jalview.gui.StructureViewer.ViewerType;
-import jalview.io.DataSourceType;
-import jalview.io.StructureFile;
-import jalview.structure.AtomSpec;
-import jalview.structure.StructureCommand;
-import jalview.structure.StructureCommandI;
-import jalview.structure.StructureSelectionManager;
-import jalview.structures.models.AAStructureBindingModel;
-
 import java.awt.Container;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
@@ -52,6 +39,20 @@ import org.jmol.api.JmolViewer;
 import org.jmol.c.CBK;
 import org.jmol.viewer.Viewer;
 
+import jalview.api.FeatureRenderer;
+import jalview.bin.Cache;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.gui.IProgressIndicator;
+import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.DataSourceType;
+import jalview.io.StructureFile;
+import jalview.structure.AtomSpec;
+import jalview.structure.StructureCommand;
+import jalview.structure.StructureCommandI;
+import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
+
 public abstract class JalviewJmolBinding extends AAStructureBindingModel
         implements JmolStatusListener, JmolSelectionListener,
         ComponentListener
@@ -111,14 +112,13 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     return getViewerTitle("Jmol", true);
   }
 
-  public void closeViewer()
+  private String jmolScript(String script)
   {
-    // remove listeners for all structures in viewer
-    getSsm().removeStructureViewerListener(this, this.getStructureFiles());
-    jmolViewer.dispose();
-    lastCommand = null;
-    jmolViewer = null;
-    releaseUIResources();
+    Cache.log.debug(">>Jmol>> " + script);
+    String s = jmolViewer.scriptWait(script);
+    Cache.log.debug("<<Jmol<< " + s);
+
+    return s;
   }
 
   @Override
@@ -133,7 +133,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     jmolHistory(false);
     if (lastCommand == null || !lastCommand.equals(cmd))
     {
-      jmolViewer.evalStringQuiet(cmd + "\n");
+      jmolScript(cmd + "\n");
     }
     jmolHistory(true);
     lastCommand = cmd;
@@ -188,7 +188,6 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   @Override
   public synchronized String[] getStructureFiles()
   {
-    List<String> mset = new ArrayList<>();
     if (jmolViewer == null)
     {
       return new String[0];
@@ -198,15 +197,23 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     {
       int modelCount = jmolViewer.ms.mc;
       String filePath = null;
+      List<String> mset = new ArrayList<>();
       for (int i = 0; i < modelCount; ++i)
       {
+        /*
+         * defensive check for null as getModelFileName can return null
+         * even when model count ms.mc is > 0
+         */
         filePath = jmolViewer.ms.getModelFileName(i);
-        if (!mset.contains(filePath))
+        if (filePath != null && !mset.contains(filePath))
         {
           mset.add(filePath);
         }
       }
-      modelFileNames = mset.toArray(new String[mset.size()]);
+      if (!mset.isEmpty())
+      {
+        modelFileNames = mset.toArray(new String[mset.size()]);
+      }
     }
 
     return modelFileNames;
@@ -241,7 +248,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     {
       if (resetLastRes.length() > 0)
       {
-        jmolViewer.evalStringQuiet(resetLastRes.toString());
+        jmolScript(resetLastRes.toString());
         resetLastRes.setLength(0);
       }
       for (AtomSpec atom : atoms)
@@ -256,59 +263,39 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   public void highlightAtom(int atomIndex, int pdbResNum, String chain,
           String pdbfile)
   {
-    if (modelFileNames == null)
-    {
-      return;
-    }
-
-    // look up file model number for this pdbfile
-    int mdlNum = 0;
-    // may need to adjust for URLencoding here - we don't worry about that yet.
-    while (mdlNum < modelFileNames.length
-            && !pdbfile.equals(modelFileNames[mdlNum]))
-    {
-      mdlNum++;
-    }
-    if (mdlNum == modelFileNames.length)
+    String modelId = getModelIdForFile(pdbfile);
+    if (modelId.isEmpty())
     {
       return;
     }
 
     jmolHistory(false);
 
+    StringBuilder selection = new StringBuilder(32);
     StringBuilder cmd = new StringBuilder(64);
-    cmd.append("select ").append(String.valueOf(pdbResNum)); // +modelNum
-
-    resetLastRes.append("select ").append(String.valueOf(pdbResNum)); // +modelNum
-
-    cmd.append(":");
-    resetLastRes.append(":");
+    selection.append("select ").append(String.valueOf(pdbResNum));
+    selection.append(":");
     if (!chain.equals(" "))
     {
-      cmd.append(chain);
-      resetLastRes.append(chain);
-    }
-    {
-      cmd.append(" /").append(String.valueOf(mdlNum + 1));
-      resetLastRes.append("/").append(String.valueOf(mdlNum + 1));
+      selection.append(chain);
     }
-    cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
+    selection.append(" /").append(modelId);
 
-    resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
-            + " and not hetero; spacefill 0;");
+    cmd.append(selection).append(";wireframe 100;").append(selection)
+            .append(" and not hetero;").append("spacefill 200;select none");
 
-    cmd.append("spacefill 200;select none");
+    resetLastRes.append(selection).append(";wireframe 0;").append(selection)
+            .append(" and not hetero; spacefill 0;");
 
-    jmolViewer.evalStringQuiet(cmd.toString());
+    jmolScript(cmd.toString());
     jmolHistory(true);
-
   }
 
   private boolean debug = true;
 
   private void jmolHistory(boolean enable)
   {
-    jmolViewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
+    jmolScript("History " + ((debug || enable) ? "on" : "off"));
   }
 
   public void loadInline(String string)
@@ -454,7 +441,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   {
     /**
      * this implements the toggle label behaviour copied from the original
-     * structure viewer, MCView
+     * structure viewer, mc_view
      */
     if (strData != null)
     {
@@ -485,7 +472,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
     if (!atomsPicked.contains(picked))
     {
-      jmolViewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
+      jmolScript("select " + picked + ";label %n %r:%c");
       atomsPicked.addElement(picked);
     }
     else
@@ -671,8 +658,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
           // see JAL-623 - need method of matching pasted data up
           {
             pdb = getSsm().setMapping(getSequence()[pe], getChains()[pe],
-                    pdbfile, DataSourceType.PASTE,
-                    getIProgressIndicator());
+                    pdbfile, DataSourceType.PASTE, getIProgressIndicator());
             getPdbEntry(modelnum).setFile("INLINE" + pdb.getId());
             matches = true;
             foundEntry = true;
@@ -740,7 +726,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     // }
     if (!isLoadingFromArchive())
     {
-      jmolViewer.evalStringQuiet(
+      jmolScript(
               "model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
     }
     // register ourselves as a listener and notify the gui that it needs to
@@ -805,7 +791,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   public void showHelp()
   {
-    showUrl("http://jmol.sourceforge.net/docs/JmolUserGuide/", "jmolHelp");
+    showUrl("http://wiki.jmol.org"
+    // BH 2018 "http://jmol.sourceforge.net/docs/JmolUserGuide/"
+            , "jmolHelp");
   }
 
   /**
@@ -822,7 +810,16 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
    */
   public abstract void showConsole(boolean show);
 
+  public static Viewer getJmolData(JmolParser jmolParser)
+  {
+    return (Viewer) JmolViewer.allocateViewer(null, null, null, null, null,
+            "-x -o -n", jmolParser);
+  }
+
   /**
+   * 
+   * 
+   * 
    * @param renderPanel
    * @param jmolfileio
    *          - when true will initialise jmol's file IO system (should be false
@@ -853,13 +850,16 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
    * @param consolePanel
    *          - panel to contain Jmol console
    * @param buttonsToShow
-   *          - buttons to show on the console, in ordr
+   *          - buttons to show on the console, in order
    */
   public void allocateViewer(Container renderPanel, boolean jmolfileio,
           String htmlName, URL documentBase, URL codeBase,
           String commandOptions, final Container consolePanel,
           String buttonsToShow)
   {
+
+    System.err.println("Allocating Jmol Viewer: " + commandOptions);
+
     if (commandOptions == null)
     {
       commandOptions = "";
@@ -871,7 +871,15 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
     jmolViewer.setJmolStatusListener(this); // extends JmolCallbackListener
 
-    console = createJmolConsole(consolePanel, buttonsToShow);
+    try
+    {
+      console = createJmolConsole(consolePanel, buttonsToShow);
+    } catch (Throwable e)
+    {
+      System.err.println("Could not create Jmol application console. "
+              + e.getMessage());
+      e.printStackTrace();
+    }
     if (consolePanel != null)
     {
       consolePanel.addComponentListener(this);
@@ -883,6 +891,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   protected abstract JmolAppConsoleInterface createJmolConsole(
           Container consolePanel, String buttonsToShow);
 
+  // BH 2018 -- Jmol console is not working due to problems with styled
+  // documents.
+
   protected org.jmol.api.JmolAppConsoleInterface console = null;
 
   @Override
@@ -957,7 +968,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     {
       if (modelFileNames[i].equalsIgnoreCase(pdbFile))
       {
-        return String.valueOf(i);
+        return String.valueOf(i + 1);
       }
     }
     return "";
@@ -974,4 +985,16 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   {
     return String.valueOf(pdbfnum + 1);
   }
+
+  /**
+   * Returns ".spt" - the Jmol session file extension
+   * 
+   * @return
+   * @see https://chemapps.stolaf.edu/jmol/docs/#writemodel
+   */
+  @Override
+  public String getSessionFileExtension()
+  {
+    return ".spt";
+  }
 }