JAL-4307 some models return null for hetatm list
[jalview.git] / src / jalview / ext / jmol / JalviewJmolBinding.java
index 038ca48..5b931e1 100644 (file)
@@ -26,11 +26,15 @@ import java.awt.event.ComponentListener;
 import java.io.File;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
+import javax.swing.SwingUtilities;
+
 import org.jmol.adapter.smarter.SmarterJmolAdapter;
 import org.jmol.api.JmolAppConsoleInterface;
 import org.jmol.api.JmolSelectionListener;
@@ -39,10 +43,14 @@ import org.jmol.api.JmolViewer;
 import org.jmol.c.CBK;
 import org.jmol.viewer.Viewer;
 
+import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
-import jalview.bin.Cache;
+import jalview.api.FeatureSettingsModelI;
+import jalview.api.SequenceRenderer;
+import jalview.bin.Console;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.gui.AppJmol;
 import jalview.gui.IProgressIndicator;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
@@ -52,6 +60,8 @@ import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
 import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
+import jalview.ws.dbsources.Pdb;
+import javajs.util.BS;
 
 public abstract class JalviewJmolBinding extends AAStructureBindingModel
         implements JmolStatusListener, JmolSelectionListener,
@@ -83,8 +93,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     setStructureCommands(new JmolCommands());
     /*
      * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
-     * "jalviewJmol", ap.av.applet .getDocumentBase(),
-     * ap.av.applet.getCodeBase(), "", this);
+     * "jalviewJmol", ap.av.applet .getDocumentBase(), ap.av.applet.getCodeBase(),
+     * "", this);
      * 
      * jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
      */
@@ -114,9 +124,22 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   private String jmolScript(String script)
   {
-    Cache.log.debug(">>Jmol>> " + script);
-    String s = jmolViewer.scriptWait(script);
-    Cache.log.debug("<<Jmol<< " + s);
+    return jmolScript(script, false);
+  }
+
+  private String jmolScript(String script, boolean useScriptWait)
+  {
+    Console.debug(">>Jmol>> " + script);
+    String s;
+    if (useScriptWait)
+    {
+      s = jmolViewer.scriptWait(script);
+    }
+    else
+    {
+      s = jmolViewer.evalStringQuiet(script); // scriptWait(script); BH
+    }
+    Console.debug("<<Jmol<< " + s);
 
     return s;
   }
@@ -142,28 +165,49 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   public void createImage(String file, String type, int quality)
   {
-    System.out.println("JMOL CREATE IMAGE");
+    jalview.bin.Console.outPrintln("JMOL CREATE IMAGE");
   }
 
   @Override
   public String createImage(String fileName, String type,
           Object textOrBytes, int quality)
   {
-    System.out.println("JMOL CREATE IMAGE");
+    jalview.bin.Console.outPrintln("JMOL CREATE IMAGE");
     return null;
   }
 
   @Override
   public String eval(String strEval)
   {
-    // System.out.println(strEval);
+    // jalview.bin.Console.outPrintln(strEval);
     // "# 'eval' is implemented only for the applet.";
     return null;
   }
 
   // End StructureListener
   // //////////////////////////
-
+  
+  ////////////////////////////
+  // HETATM get
+  //
+  
+  @Override
+  public List<String> getHetatmNames()
+  {
+    HashMap<String,String> hetlist=new HashMap();
+    for (int mc=0;mc<jmolViewer.ms.mc; mc++)
+    {
+      Map<String,String> hets = jmolViewer.ms.getHeteroList(mc);
+      if (hets!=null)
+      {
+        hetlist.putAll(hets);
+      }
+    }
+    return Arrays.asList(hetlist.keySet().toArray(new String[0]));
+  }
+  //
+  ////////////////////////////
+  
   @Override
   public float[][] functionXY(String functionName, int x, int y)
   {
@@ -201,8 +245,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       for (int i = 0; i < modelCount; ++i)
       {
         /*
-         * defensive check for null as getModelFileName can return null
-         * even when model count ms.mc is > 0
+         * defensive check for null as getModelFileName can return null even when model
+         * count ms.mc is > 0
          */
         filePath = jmolViewer.ms.getModelFileName(i);
         if (filePath != null && !mset.contains(filePath))
@@ -251,26 +295,63 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
         jmolScript(resetLastRes.toString());
         resetLastRes.setLength(0);
       }
+      StringBuilder highlightCommands=null;
       for (AtomSpec atom : atoms)
       {
-        highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
+        StringBuilder thisAtom = highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
                 atom.getChain(), atom.getPdbFile());
+        if (thisAtom!=null) {
+          if (highlightCommands==null)
+          {
+            highlightCommands=thisAtom;                  
+          } else {
+            highlightCommands.append(thisAtom);
+          }
+        }
       }
+      if (highlightCommands!=null)
+      {
+        jmolHistory(false);
+        jmolScript(highlightCommands.toString());
+        jmolHistory(true);
+      }
+      // Highlight distances between atoms with a 'measure' command - not yet
+      // working
+      // if (atoms.size() >= 2)
+      // {
+      // StringBuilder sb = new StringBuilder();
+      // for (int a = 0; a < atoms.size(); a++)
+      // {
+      // AtomSpec speca = atoms.get(a);
+      // String a_model = getModelIdForFile(speca.getPdbFile());
+      // for (int b = a + 1; b < atoms.size(); b++)
+      // {
+      // AtomSpec specb = atoms.get(b);
+      // String b_model = getModelIdForFile(speca.getPdbFile());
+      // sb.append("measure ALL (" + speca.getAtomIndex() + " and */"
+      // + a_model + ") (" + specb.getAtomIndex() + " and */"
+      // + b_model + ");");
+      // }
+      // }
+      // jmolHistory(false, useScriptWait);
+      // jmolScript(sb.toString(), useScriptWait);
+      // jmolHistory(true, useScriptWait);
+      // }
+
     }
+
   }
 
   // jmol/ssm only
-  public void highlightAtom(int atomIndex, int pdbResNum, String chain,
+  private StringBuilder highlightAtom(int atomIndex, int pdbResNum, String chain,
           String pdbfile)
   {
     String modelId = getModelIdForFile(pdbfile);
     if (modelId.isEmpty())
     {
-      return;
+      return null;
     }
 
-    jmolHistory(false);
-
     StringBuilder selection = new StringBuilder(32);
     StringBuilder cmd = new StringBuilder(64);
     selection.append("select ").append(String.valueOf(pdbResNum));
@@ -287,15 +368,20 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     resetLastRes.append(selection).append(";wireframe 0;").append(selection)
             .append(" and not hetero; spacefill 0;");
 
-    jmolScript(cmd.toString());
-    jmolHistory(true);
+    return cmd;
   }
 
   private boolean debug = true;
 
   private void jmolHistory(boolean enable)
   {
-    jmolScript("History " + ((debug || enable) ? "on" : "off"));
+    jmolHistory(enable, false);
+  }
+
+  private void jmolHistory(boolean enable, boolean useScriptWait)
+  {
+    jmolScript("History " + ((debug || enable) ? "on" : "off"),
+            useScriptWait);
   }
 
   public void loadInline(String string)
@@ -395,8 +481,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     }
 
     /*
-     * highlight position on alignment(s); if some text is returned, 
-     * show this as a second line on the structure hover tooltip
+     * highlight position on alignment(s); if some text is returned, show this as a
+     * second line on the structure hover tooltip
      */
     String label = getSsm().mouseOverStructure(pdbResNum, chainId,
             pdbfilename);
@@ -424,7 +510,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     lastMessage = strInfo;
     if (data != null)
     {
-      System.err.println("Ignoring additional hover info: " + data
+      jalview.bin.Console.errPrintln("Ignoring additional hover info: " + data
               + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
     }
     mouseOverStructure(atomIndex, strInfo);
@@ -432,8 +518,8 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   /*
    * { if (history != null && strStatus != null &&
-   * !strStatus.equals("Script completed")) { history.append("\n" + strStatus);
-   * } }
+   * !strStatus.equals("Script completed")) { history.append("\n" + strStatus); }
+   * }
    */
 
   public void notifyAtomPicked(int atomIndex, String strInfo,
@@ -445,7 +531,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
      */
     if (strData != null)
     {
-      System.err.println("Ignoring additional pick data string " + strData);
+      jalview.bin.Console.errPrintln("Ignoring additional pick data string " + strData);
     }
     int chainSeparator = strInfo.indexOf(":");
     int p = 0;
@@ -494,6 +580,28 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   @Override
   public void notifyCallback(CBK type, Object[] data)
   {
+    /*
+     * ensure processed in AWT thread to avoid risk of deadlocks
+     */
+    SwingUtilities.invokeLater(new Runnable()
+    {
+
+      @Override
+      public void run()
+      {
+        processCallback(type, data);
+      }
+    });
+  }
+
+  /**
+   * Processes one callback notification from Jmol
+   * 
+   * @param type
+   * @param data
+   */
+  protected void processCallback(CBK type, Object[] data)
+  {
     try
     {
       switch (type)
@@ -525,7 +633,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
                 (data == null) ? ((String) null) : (String) data[1]);
         break;
       case ERROR:
-        // System.err.println("Ignoring error callback.");
+        // jalview.bin.Console.errPrintln("Ignoring error callback.");
         break;
       case SYNC:
       case RESIZE:
@@ -535,13 +643,13 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
       case CLICK:
       default:
-        System.err.println(
+        jalview.bin.Console.errPrintln(
                 "Unhandled callback " + type + " " + data[1].toString());
         break;
       }
     } catch (Exception e)
     {
-      System.err.println("Squashed Jmol callback handler error:");
+      jalview.bin.Console.errPrintln("Squashed Jmol callback handler error:");
       e.printStackTrace();
     }
   }
@@ -595,6 +703,11 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
     modelFileNames = null;
     boolean notifyLoaded = false;
     String[] modelfilenames = getStructureFiles();
+    if (modelfilenames == null)
+    {
+      // Jmol is still loading files!
+      return;
+    }
     // first check if we've lost any structures
     if (oldmodels != null && oldmodels.length > 0)
     {
@@ -737,7 +850,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       FeatureRenderer fr = getFeatureRenderer(null);
       if (fr != null)
       {
-        fr.featuresAdded();
+        FeatureSettingsModelI colours = new Pdb().getFeatureColourScheme();
+        ((AppJmol) getViewer()).getAlignmentPanel().av
+                .applyFeaturesStyle(colours);
       }
       refreshGUI();
       loadNotifiesHandled++;
@@ -766,8 +881,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   public abstract void sendConsoleEcho(String strEcho); /*
                                                          * { showConsole(true);
                                                          * 
-                                                         * history.append("\n" +
-                                                         * strEcho); }
+                                                         * history.append("\n" + strEcho); }
                                                          */
 
   // /End JmolStatusListener
@@ -784,7 +898,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   public void setCallbackFunction(String callbackType,
           String callbackFunction)
   {
-    System.err.println("Ignoring set-callback request to associate "
+    jalview.bin.Console.errPrintln("Ignoring set-callback request to associate "
             + callbackType + " with function " + callbackFunction);
 
   }
@@ -858,7 +972,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
           String buttonsToShow)
   {
 
-    System.err.println("Allocating Jmol Viewer: " + commandOptions);
+    jalview.bin.Console.errPrintln("Allocating Jmol Viewer: " + commandOptions);
 
     if (commandOptions == null)
     {
@@ -876,7 +990,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
       console = createJmolConsole(consolePanel, buttonsToShow);
     } catch (Throwable e)
     {
-      System.err.println("Could not create Jmol application console. "
+      jalview.bin.Console.errPrintln("Could not create Jmol application console. "
               + e.getMessage());
       e.printStackTrace();
     }
@@ -997,4 +1111,23 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
   {
     return ".spt";
   }
+
+  @Override
+  public void selectionChanged(BS arg0)
+  {
+    // TODO Auto-generated method stub
+
+  }
+
+  @Override
+  public SequenceRenderer getSequenceRenderer(AlignmentViewPanel avp)
+  {
+    return new jalview.gui.SequenceRenderer(avp.getAlignViewport());
+  }
+
+  @Override
+  public String getHelpURL()
+  {
+    return "http://wiki.jmol.org"; // BH 2018
+  }
 }