Merge branch 'develop' into feature/JAL-3390hideUnmappedStructure
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 29 Jun 2020 08:10:04 +0000 (09:10 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 29 Jun 2020 08:10:04 +0000 (09:10 +0100)
Conflicts:
src/jalview/ext/jmol/JmolCommands.java
src/jalview/ext/pymol/PymolCommands.java
src/jalview/ext/rbvi/chimera/ChimeraCommands.java
src/jalview/ext/rbvi/chimera/ChimeraXCommands.java
src/jalview/gui/JalviewChimeraBindingModel.java
src/jalview/structure/StructureCommandsBase.java
src/jalview/structure/StructureCommandsI.java
src/jalview/structures/models/AAStructureBindingModel.java
test/jalview/ext/pymol/PymolCommandsTest.java
test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java
test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java

14 files changed:
1  2 
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/jalview/ext/jmol/JmolCommands.java
src/jalview/ext/pymol/PymolCommands.java
src/jalview/ext/rbvi/chimera/ChimeraCommands.java
src/jalview/ext/rbvi/chimera/ChimeraXCommands.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/gui/ChimeraViewFrame.java
src/jalview/gui/JalviewChimeraBindingModel.java
src/jalview/structure/StructureCommandsBase.java
src/jalview/structure/StructureCommandsI.java
src/jalview/structures/models/AAStructureBindingModel.java
test/jalview/ext/pymol/PymolCommandsTest.java
test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java
test/jalview/ext/rbvi/chimera/ChimeraXCommandsTest.java

@@@ -818,13 -806,13 +806,13 @@@ public class ChimeraManage
     * 
     * @param command
     *          Command string to be send.
--   * @param reply
++   * @param getReply
     *          Flag indicating whether the method should return the reply from
     *          Chimera or not.
     * @return List of Strings corresponding to the lines in the Chimera reply or
     *         <code>null</code>.
     */
--  public List<String> sendChimeraCommand(String command, boolean reply)
++  public List<String> sendChimeraCommand(String command, boolean getReply)
    {
      System.out.println("chimeradebug>> " + command);
      if (!isChimeraLaunched() || command == null
      long startTime = System.currentTimeMillis();
      try
      {
--      return sendRestCommand(command);
++      return sendRestCommand(command, getReply);
      } finally
      {
        /*
     * Sends the command to Chimera's REST API, and returns any response lines.
     * 
     * @param command
++   * @param getReply 
     * @return
     */
--  protected List<String> sendRestCommand(String command)
++  protected List<String> sendRestCommand(String command, boolean getReply)
    {
      String restUrl = "http://127.0.0.1:" + this.chimeraRestPort + "/run";
      List<NameValuePair> commands = new ArrayList<>(1);
                        CONNECTION_TIMEOUT_MS, REST_REPLY_TIMEOUT_MS)
                : HttpClientUtils.doHttpUrlPost(restUrl, commands,
                        CONNECTION_TIMEOUT_MS, REST_REPLY_TIMEOUT_MS);
++      if (!getReply)
++      {
++        return null;
++      }
        String line = "";
        while ((line = response.readLine()) != null)
        {
@@@ -460,26 -477,8 +460,31 @@@ public class JmolCommands extends Struc
    }
  
    @Override
 +  public StructureCommandI showStructures(AtomSpecModel restrictTo)
 +  {
 +    if (restrictTo == null)
 +    {
 +      return new StructureCommand("display *; cartoon only");
 +    }
 +    String atomSpec = getAtomSpec(restrictTo, false);
 +    String cmd = "display " + atomSpec + "; select displayed; cartoon only";
 +    return new StructureCommand(cmd);
 +  }
 +
 +  @Override
 +  public StructureCommandI hideChain(String modelId, String chainId)
 +  {
 +    return new StructureCommand("hide add :" + chainId + "/" + modelId);
 +  }
 +
 +  @Override
 +  public StructureCommandI hideAll()
 +  {
 +    return new StructureCommand("hide *");
 +  }
++
+   public StructureCommandI closeViewer()
+   {
+     return null; // not an external viewer
+   }
  }
@@@ -22,29 -23,31 +23,36 @@@ import jalview.structure.StructureComma
   */
  public class PymolCommands extends StructureCommandsBase
  {
 +  private static final StructureCommand SHOW_RIBBON = new StructureCommand("show", "ribbon");
 +
 +  private static final StructureCommand SHOW_CARTOON = new StructureCommand("show", "cartoon");
 +
 +  private static final StructureCommand HIDE_EVERYTHING = new StructureCommand("hide", "everything");
 +
-   private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand("spectrum", "chain");
-   private static final List<StructureCommandI> COLOR_BY_CHARGE = new ArrayList<>();
-   private static final List<StructureCommandI> SHOW_BACKBONE = new ArrayList<>();
-   static {
-     COLOR_BY_CHARGE.add(new StructureCommand("color", "white", "*"));
-     COLOR_BY_CHARGE
-             .add(new StructureCommand("color", "red", "resn ASP resn GLU"));
-     COLOR_BY_CHARGE.add(
-             new StructureCommand("color", "blue", "resn LYS resn ARG"));
-     COLOR_BY_CHARGE
-             .add(new StructureCommand("color", "yellow", "resn CYS"));
-     SHOW_BACKBONE.add(HIDE_EVERYTHING);
-     SHOW_BACKBONE.add(SHOW_RIBBON);
-   }
+   // https://pymol.org/dokuwiki/doku.php?id=command:zoom
+   // not currently documented on
+   // https://pymolwiki.org/index.php/Category:Commands
+   private static final StructureCommand FOCUS_VIEW = new StructureCommand(
+           "zoom");
+   // https://pymolwiki.org/index.php/Quit
+   private static final StructureCommand CLOSE_PYMOL = new StructureCommand(
+           "quit");
+   // not currently documented on
+   // https://pymolwiki.org/index.php/Category:Commands
+   private static final StructureCommand COLOUR_BY_CHAIN = new StructureCommand(
+           "spectrum", "chain");
 -
+   private static final List<StructureCommandI> COLOR_BY_CHARGE = Arrays
+           .asList(new StructureCommand("color", "white", "*"),
+                   new StructureCommand("color", "red", "resn ASP resn GLU"),
+                   new StructureCommand("color", "blue",
+                           "resn LYS resn ARG"),
+                   new StructureCommand("color", "yellow", "resn CYS"));
+   private static final List<StructureCommandI> SHOW_BACKBONE = Arrays
+           .asList(new StructureCommand("hide", "everything"),
+                   new StructureCommand("show", "ribbon"));
  
    @Override
    public StructureCommandI colourByChain()
    }
  
    @Override
 +  public StructureCommandI showStructures(AtomSpecModel restrictTo)
 +  {
 +    if (restrictTo == null)
 +    {
 +      return SHOW_CARTOON;
 +    }
 +    else
 +    {
 +      return new StructureCommand("show", "cartoon",
 +              getAtomSpec(restrictTo, false));
 +    }
 +  }
 +
 +  @Override
 +  public StructureCommandI hideChain(String modelId, String chainId)
 +  {
 +    return new StructureCommand("hide", modelId + "//" + chainId + "//");
 +  }
 +
 +  @Override
 +  public StructureCommandI hideAll()
 +  {
 +    return HIDE_EVERYTHING;
 +  }
++    
+   public StructureCommandI closeViewer()
+   {
 -    // https://pymolwiki.org/index.php/Quit
+     return CLOSE_PYMOL;
+   }
  
  }
@@@ -374,29 -424,50 +391,74 @@@ public class ChimeraCommands extends St
    }
  
    @Override
 +  public StructureCommandI showStructures(AtomSpecModel restrictTo)
 +  {
 +    if (restrictTo == null)
 +    {
 +      return new StructureCommand("ribbon");
 +    }
 +
 +    String atomSpec = getAtomSpec(restrictTo, false);
 +    String cmd = "ribbon " + atomSpec;
 +    return new StructureCommand(cmd);
 +  }
 +
 +  @Override
 +  public StructureCommandI hideChain(String modelId, String chainId)
 +  {
 +    String cmd = "~ribbon #" + modelId + ":." + chainId;
 +    return new StructureCommand(cmd);
 +  }
 +
 +  @Override
 +  public StructureCommandI hideAll()
 +  {
 +    return new StructureCommand("~display; ~ribbon");
 +  }
+   public StructureCommandI closeViewer()
+   {
+     return CLOSE_CHIMERA;
+   }
+   @Override
+   public List<StructureCommandI> startNotifications(String uri)
+   {
+     // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/listen.html
+     List<StructureCommandI> cmds = new ArrayList<>();
+     cmds.add(new StructureCommand("listen start models url " + uri));
+     cmds.add(new StructureCommand("listen start select prefix SelectionChanged url " + uri));
+     return cmds;
+   }
+   @Override
+   public List<StructureCommandI> stopNotifications()
+   {
+     List<StructureCommandI> cmds = new ArrayList<>();
+     cmds.add(STOP_NOTIFY_MODELS);
+     cmds.add(STOP_NOTIFY_SELECTION);
+     return cmds;
+   }
+   @Override
+   public StructureCommandI getSelectedResidues()
+   {
+     return GET_SELECTION;
+   }
+   @Override
+   public StructureCommandI listResidueAttributes()
+   {
+     return LIST_RESIDUE_ATTRIBUTES;
+   }
+   @Override
+   public StructureCommandI getResidueAttributes(String attName)
+   {
+     // this alternative command
+     // list residues spec ':*/attName' attr attName
+     // doesn't report 'None' values (which is good), but
+     // fails for 'average.bfactor' (which is bad):
+     return new StructureCommand("list residues attr '" + attName + "'");
+   }
  
  }
@@@ -33,6 -35,21 +34,25 @@@ import jalview.structure.StructureComma
   */
  public class ChimeraXCommands extends ChimeraCommands
  {
+   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#resattr
 -  private static final StructureCommand LIST_RESIDUE_ATTRIBUTES = new StructureCommand("info resattr");
++  private static final StructureCommand LIST_RESIDUE_ATTRIBUTES = new StructureCommand(
++          "info resattr");
+   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/exit.html
 -  private static final StructureCommand CLOSE_CHIMERAX = new StructureCommand("exit");
++  private static final StructureCommand CLOSE_CHIMERAX = new StructureCommand(
++          "exit");
+   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#notify
 -  private static final StructureCommand STOP_NOTIFY_SELECTION = new StructureCommand("info notify stop selection jalview");
++  private static final StructureCommand STOP_NOTIFY_SELECTION = new StructureCommand(
++          "info notify stop selection jalview");
 -  private static final StructureCommand STOP_NOTIFY_MODELS = new StructureCommand("info notify stop models jalview");
++  private static final StructureCommand STOP_NOTIFY_MODELS = new StructureCommand(
++          "info notify stop models jalview");
+   // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#selection
+   private static final StructureCommand GET_SELECTION = new StructureCommand(
+           "info selection level residue");
    private static final StructureCommand SHOW_BACKBONE = new StructureCommand(
            "~display all;~ribbon;show @CA|P atoms");
  
    }
  
    @Override
 +  public StructureCommandI hideChain(String modelId, String chainId)
 +  {
 +    String cmd = "~ribbon #" + modelId + "/" + chainId;
 +    return new StructureCommand(cmd);
 +  }
++
+   public StructureCommandI closeViewer()
+   {
+     return CLOSE_CHIMERAX;
+   }
+   @Override
+   public List<StructureCommandI> startNotifications(String uri)
+   {
+     List<StructureCommandI> cmds = new ArrayList<>();
 -    cmds.add(new StructureCommand("info notify start models prefix ModelChanged jalview url " + uri));
 -    cmds.add(new StructureCommand("info notify start selection jalview prefix SelectionChanged url " + uri));
++    cmds.add(new StructureCommand(
++            "info notify start models prefix ModelChanged jalview url "
++                    + uri));
++    cmds.add(new StructureCommand(
++            "info notify start selection jalview prefix SelectionChanged url "
++                    + uri));
+     return cmds;
+   }
+   @Override
+   public List<StructureCommandI> stopNotifications()
+   {
+     List<StructureCommandI> cmds = new ArrayList<>();
+     cmds.add(STOP_NOTIFY_MODELS);
+     cmds.add(STOP_NOTIFY_SELECTION);
+     return cmds;
+   }
+   @Override
+   public StructureCommandI getSelectedResidues()
+   {
+     return GET_SELECTION;
+   }
+   @Override
+   public StructureCommandI listResidueAttributes()
+   {
+     return LIST_RESIDUE_ATTRIBUTES;
+   }
  }
Simple merge
@@@ -149,28 -168,52 +149,78 @@@ public interface StructureCommands
    StructureCommandI openSession(String filepath);
  
    /**
 +   * Returns a command to show structures in the viewer. If {@code restrictTo}
 +   * is null, all structures are included, otherwise the display is restricted
 +   * to positions represented in the model
 +   * 
 +   * @param restrictTo
 +   * @return
 +   */
 +  StructureCommandI showStructures(AtomSpecModel restrictTo);
 +
 +  /**
 +   * Returns a command to hide the specified model chain in the structure viewer
 +   * 
 +   * @param modelId
 +   * @param chainId
 +   * @return
 +   */
 +  StructureCommandI hideChain(String modelId, String chainId);
 +
 +  /**
 +   * Returns a command to hide everything in the structure viewer
 +   * 
 +   * @return
 +   */
 +  StructureCommandI hideAll();
++
++  /**
+    * Returns a command to ask the viewer to close down
+    * 
+    * @return
+    */
+   StructureCommandI closeViewer();
+   /**
+    * Returns one or more commands to ask the viewer to notify model or selection
+    * changes to the given uri. Returns null if this is not supported by the
+    * structure viewer.
+    * 
+    * @param uri
+    * @return
+    */
+   List<StructureCommandI> startNotifications(String uri);
+   /**
+    * Returns one or more commands to ask the viewer to stop notifying model or
+    * selection changes. Returns null if this is not supported by the structure
+    * viewer.
+    * 
+    * @return
+    */
+   List<StructureCommandI> stopNotifications();
+   /**
+    * Returns a command to ask the viewer for its current residue selection, or
+    * null if no such command is supported
+    * 
+    * @return
+    */
+   StructureCommandI getSelectedResidues();
+   /**
+    * Returns a command to list the unique names of residue attributes, or null
+    * if no such command is supported
+    * 
+    * @return
+    */
+   StructureCommandI listResidueAttributes();
+   /**
+    * Returns a command to list residues with an attribute of the given name,
+    * with attribute value, or null if no such command is supported
+    * 
+    * @return
+    */
+   StructureCommandI getResidueAttributes(String attName);
  }
@@@ -178,16 -177,8 +179,18 @@@ public abstract class AAStructureBindin
  
    public String fileLoadingError;
  
 +  private boolean showAlignmentOnly;
 +
 +  /*
 +   * a list of chains "pdbid:chainid" to hide in the viewer
 +   */
 +  // TODO make private once deprecated JalviewJmolBinding.centerViewer removed
 +  protected List<String> chainsToHide;
 +
 +  private boolean hideHiddenRegions;
 +
+   protected Thread externalViewerMonitor;
    /**
     * Constructor
     * 
    private List<String> executeCommand(StructureCommandI cmd,
            boolean getReply, String msg)
    {
 +    if (cmd == null)
 +    {
 +      return null; // catch unimplemented commands
 +    }
+     final JalviewStructureDisplayI theViewer = getViewer();
+     final long handle = msg == null ? 0 : theViewer.startProgressBar(msg);
      if (getReply)
      {
        /*
@@@ -337,37 -343,8 +337,42 @@@ public class PymolCommandsTes
    }
  
    @Test(groups = "Functional")
 +  public void testHideAll()
 +  {
 +    StructureCommandI cmd = testee.hideAll();
 +    assertEquals(cmd, new StructureCommand("hide", "everything"));
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testHideChain()
 +  {
 +    StructureCommandI cmd = testee.hideChain("1.1", "B");
 +    assertEquals(cmd, new StructureCommand("hide", "1.1//B//"));
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testShowStructures()
 +  {
 +    /*
 +     * with nothing excluded
 +     */
 +    StructureCommandI cmd = testee.showStructures(null);
 +    assertEquals(cmd, new StructureCommand("show", "cartoon"));
 +
 +    /*
 +     * restricted to specified positions
 +     */
 +    AtomSpecModel restrictTo = new AtomSpecModel();
 +    restrictTo.addRange("1.1", 12, 20, "A");
 +    restrictTo.addRange("1.1", 30, 35, "A");
 +    restrictTo.addRange("2.1", 11, 30, "B");
 +    cmd = testee.showStructures(restrictTo);
 +    assertEquals(cmd, new StructureCommand("show", "cartoon",
 +            "1.1//A/12-20+30-35/ 2.1//B/11-30/"));
 +  }
++
+   public void testCloseViewer()
+   {
+     assertEquals(testee.closeViewer(), new StructureCommand("quit"));
+   }
  }
@@@ -341,37 -350,47 +342,81 @@@ public class ChimeraCommandsTes
    }
  
    @Test(groups = "Functional")
 +  public void testHideAll()
 +  {
 +    StructureCommandI cmd = testee.hideAll();
-     assertEquals(cmd.getCommand(), "~display all; ~ribbon");
++    assertEquals(cmd.getCommand(), "~display; ~ribbon");
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testHideChain()
 +  {
 +    StructureCommandI cmd = testee.hideChain("1.1", "B");
 +    assertEquals(cmd.getCommand(), "~ribbon #1.1:.B");
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testShowStructures()
 +  {
 +    /*
 +     * with nothing excluded
 +     */
 +    StructureCommandI cmd = testee.showStructures(null);
 +    assertEquals(cmd.getCommand(), "ribbon");
 +
 +    /*
 +     * restricted to specified positions
 +     */
 +    AtomSpecModel restrictTo = new AtomSpecModel();
 +    restrictTo.addRange("1.1", 12, 20, "A");
 +    restrictTo.addRange("1.1", 30, 35, "A");
 +    restrictTo.addRange("2.1", 11, 30, "B");
 +    cmd = testee.showStructures(restrictTo);
 +    assertEquals(cmd.getCommand(),
 +            "ribbon #1.1:12-20.A,30-35.A|#2.1:11-30.B");
 +  }
++
+   public void testCloseViewer()
+   {
+     assertEquals(testee.closeViewer(), new StructureCommand("stop really"));
+   }
+   @Test(groups = "Functional")
+   public void testGetSelectedResidues()
+   {
+     assertEquals(testee.getSelectedResidues(),
+             new StructureCommand("list selection level residue"));
+   }
+   @Test(groups = "Functional")
+   public void testListResidueAttributes()
+   {
+     assertEquals(testee.listResidueAttributes(),
+             new StructureCommand("list resattr"));
+   }
+   @Test(groups = "Functional")
+   public void testGetResidueAttributes()
+   {
+     assertEquals(testee.getResidueAttributes("binding site"),
+             new StructureCommand("list residues attr 'binding site'"));
+   }
+   @Test(groups = "Functional")
+   public void testStartNotifications()
+   {
+     List<StructureCommandI> cmds = testee.startNotifications("to here");
+     assertEquals(cmds.size(), 2);
+     assertEquals(cmds.get(0), new StructureCommand("listen start models url to here"));
+     assertEquals(cmds.get(1), new StructureCommand("listen start select prefix SelectionChanged url to here"));
+   }
+   @Test(groups = "Functional")
+   public void testStopNotifications()
+   {
+     List<StructureCommandI> cmds = testee.stopNotifications();
+     assertEquals(cmds.size(), 2);
+     assertEquals(cmds.get(0), new StructureCommand("listen stop models"));
+     assertEquals(cmds.get(1), new StructureCommand("listen stop selection"));
+   }
  }
@@@ -318,37 -325,40 +319,74 @@@ public class ChimeraXCommandsTes
    }
  
    @Test(groups = "Functional")
 +  public void testHideAll()
 +  {
 +    StructureCommandI cmd = testee.hideAll();
-     assertEquals(cmd.getCommand(), "~display all; ~ribbon");
++    assertEquals(cmd.getCommand(), "~display; ~ribbon");
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testHideChain()
 +  {
 +    StructureCommandI cmd = testee.hideChain("1.1", "B");
 +    assertEquals(cmd.getCommand(), "~ribbon #1.1/B");
 +  }
 +
 +  @Test(groups = "Functional")
 +  public void testShowStructures()
 +  {
 +    /*
 +     * with nothing excluded
 +     */
 +    StructureCommandI cmd = testee.showStructures(null);
 +    assertEquals(cmd.getCommand(), "ribbon");
 +
 +    /*
 +     * restricted to specified positions
 +     */
 +    AtomSpecModel restrictTo = new AtomSpecModel();
 +    restrictTo.addRange("1.1", 12, 20, "A");
 +    restrictTo.addRange("1.1", 30, 35, "A");
 +    restrictTo.addRange("2.1", 11, 30, "B");
 +    cmd = testee.showStructures(restrictTo);
 +    assertEquals(cmd.getCommand(),
 +            "ribbon #1.1/A:12-20,30-35|#2.1/B:11-30");
 +  }
++
+   public void testCloseViewer()
+   {
+     assertEquals(testee.closeViewer(), new StructureCommand("exit"));
+   }
+   @Test(groups = "Functional")
+   public void testGetSelectedResidues()
+   {
+     assertEquals(testee.getSelectedResidues(),
+             new StructureCommand("info selection level residue"));
+   }
+   @Test(groups = "Functional")
+   public void testStartNotifications()
+   {
+     List<StructureCommandI> cmds = testee.startNotifications("to here");
+     assertEquals(cmds.size(), 2);
+     assertEquals(cmds.get(0), new StructureCommand("info notify start models prefix ModelChanged jalview url to here"));
+     assertEquals(cmds.get(1), new StructureCommand("info notify start selection jalview prefix SelectionChanged url to here"));
+   }
+   @Test(groups = "Functional")
+   public void testStopNotifications()
+   {
+     List<StructureCommandI> cmds = testee.stopNotifications();
+     assertEquals(cmds.size(), 2);
+     assertEquals(cmds.get(0), new StructureCommand("info notify stop models jalview"));
+     assertEquals(cmds.get(1), new StructureCommand("info notify stop selection jalview"));
+   }
+   @Test(groups = "Functional")
+   public void testListResidueAttributes()
+   {
+     assertEquals(testee.listResidueAttributes(),
+             new StructureCommand("info resattr"));
+   }
  }