JAL-2422 a fix and a fudge for two failing ChimeraX commands
[jalview.git] / src / jalview / ext / rbvi / chimera / ChimeraXCommands.java
index 5eba203..ad04fc9 100644 (file)
  */
 package jalview.ext.rbvi.chimera;
 
-import jalview.structure.AtomSpecModel;
-import jalview.util.ColorUtils;
-import jalview.util.IntRangeComparator;
-
 import java.awt.Color;
-import java.util.Collections;
-import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
+import jalview.structure.AtomSpecModel;
+import jalview.structure.StructureCommand;
+import jalview.structure.StructureCommandI;
+
 /**
  * Routines for generating ChimeraX commands for Jalview/ChimeraX binding
  */
 public class ChimeraXCommands extends ChimeraCommands
 {
-  private static final String CMD_COLOUR_BY_CHARGE = "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow";
+  // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/info.html#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");
+
+  // 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_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");
+
+  // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/view.html
+  private static final StructureCommand FOCUS_VIEW = new StructureCommand(
+          "view");
+
+  private static final StructureCommandI COLOUR_BY_CHARGE = new StructureCommand(
+          "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow");
 
   @Override
-  public String colourByCharge()
+  public List<StructureCommandI> colourByCharge()
   {
-    return CMD_COLOUR_BY_CHARGE;
+    return Arrays.asList(COLOUR_BY_CHARGE);
   }
 
   @Override
@@ -49,26 +72,18 @@ public class ChimeraXCommands extends ChimeraCommands
   }
 
   @Override
-  public String setBackgroundColour(Color col)
-  {
-    // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/set.html
-    return "set bgColor " + ColorUtils.toTkCode(col);
-  }
-
-  @Override
-  public String getColourCommand(String atomSpec, Color colour)
+  public StructureCommandI colourResidues(String atomSpec, Color colour)
   {
     // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/color.html
     String colourCode = getColourString(colour);
 
-    return "color " + atomSpec + " " + colourCode;
+    return new StructureCommand("color " + atomSpec + " " + colourCode);
   }
 
   @Override
-  public String focusView()
+  public StructureCommandI focusView()
   {
-    // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/view.html
-    return "view";
+    return FOCUS_VIEW;
   }
 
   /**
@@ -96,7 +111,7 @@ public class ChimeraXCommands extends ChimeraCommands
    * @return
    */
   @Override
-  protected String setAttribute(String attributeName,
+  protected StructureCommandI setAttribute(String attributeName,
           String attributeValue, AtomSpecModel atomSpecModel)
   {
     StringBuilder sb = new StringBuilder(128);
@@ -104,21 +119,22 @@ public class ChimeraXCommands extends ChimeraCommands
     sb.append(" res ").append(attributeName).append(" '")
             .append(attributeValue).append("'");
     sb.append(" create true");
-    return sb.toString();
+    return new StructureCommand(sb.toString());
   }
 
   @Override
-  public String openCommandFile(String path)
+  public StructureCommandI openCommandFile(String path)
   {
     // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html
-    return "open " + path;
+    return new StructureCommand("open " + path);
   }
 
   @Override
-  public String saveSession(String filepath)
+  public StructureCommandI saveSession(String filepath)
   {
     // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/save.html
-    return "save session " + filepath;
+    // note ChimeraX will append ".cxs" to the filepath!
+    return new StructureCommand("save " + filepath + " format session");
   }
 
   /**
@@ -133,7 +149,7 @@ public class ChimeraXCommands extends ChimeraCommands
   {
     StringBuilder sb = new StringBuilder(128);
     boolean firstModel = true;
-    for (Integer model : atomSpec.getModels())
+    for (String model : atomSpec.getModels())
     {
       if (!firstModel)
       {
@@ -143,7 +159,8 @@ public class ChimeraXCommands extends ChimeraCommands
       appendModel(sb, model, atomSpec);
       if (alphaOnly)
       {
-        sb.append("@CA|P");
+        // TODO @P if RNA - add nucleotide flag to AtomSpecModel?
+        sb.append("@CA");
       }
       // todo: is there ChimeraX syntax to exclude altlocs?
     }
@@ -157,7 +174,7 @@ public class ChimeraXCommands extends ChimeraCommands
    * @param model
    * @param atomSpec
    */
-  protected void appendModel(StringBuilder sb, Integer model,
+  protected void appendModel(StringBuilder sb, String model,
           AtomSpecModel atomSpec)
   {
     sb.append("#").append(model);
@@ -167,67 +184,36 @@ public class ChimeraXCommands extends ChimeraCommands
       boolean firstPositionForChain = true;
       sb.append("/").append(chain.trim()).append(":");
       List<int[]> rangeList = atomSpec.getRanges(model, chain);
-
-      /*
-       * sort ranges into ascending start position order
-       */
-      Collections.sort(rangeList, IntRangeComparator.ASCENDING);
-
-      int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
-      int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
-
-      Iterator<int[]> iterator = rangeList.iterator();
-      while (iterator.hasNext())
+      boolean first = true;
+      for (int[] range : rangeList)
       {
-        int[] range = iterator.next();
-        if (range[0] <= end + 1)
-        {
-          /*
-           * range overlaps or is contiguous with the last one
-           * - so just extend the end position, and carry on
-           * (unless this is the last in the list)
-           */
-          end = Math.max(end, range[1]);
-        }
-        else
+        if (!first)
         {
-          /*
-           * we have a break so append the last range
-           */
-          appendRange(sb, start, end, chain, firstPositionForChain, true);
-          start = range[0];
-          end = range[1];
-          firstPositionForChain = false;
+          sb.append(",");
         }
+        first = false;
+        appendRange(sb, range[0], range[1], chain, firstPositionForChain,
+                true);
       }
-
-      /*
-       * and append the last range
-       */
-      if (!rangeList.isEmpty())
-      {
-        appendRange(sb, start, end, chain, firstPositionForChain, true);
-      }
-      firstPositionForChain = false;
     }
   }
 
   @Override
-  public String showBackbone()
+  public List<StructureCommandI> showBackbone()
   {
-    return "~display all;show @CA|P pbonds";
+    return Arrays.asList(SHOW_BACKBONE);
   }
 
   @Override
-  public String superposeStructures(AtomSpecModel spec, AtomSpecModel ref)
+  public List<StructureCommandI> superposeStructures(AtomSpecModel ref,
+          AtomSpecModel spec)
   {
     /*
      * Form ChimeraX match command to match spec to ref
      * 
      * match #1/A:2-94 toAtoms #2/A:1-93
      * 
-     * @see
-     * https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
+     * @see https://www.cgl.ucsf.edu/chimerax/docs/user/commands/align.html
      */
     StringBuilder cmd = new StringBuilder();
     String atomSpec = getAtomSpec(spec, true);
@@ -242,7 +228,50 @@ public class ChimeraXCommands extends ChimeraCommands
     cmd.append(getAtomSpec(spec, false)).append("|");
     cmd.append(getAtomSpec(ref, false)).append("; view");
 
-    return cmd.toString();
+    return Arrays.asList(new StructureCommand(cmd.toString()));
   }
 
+  @Override
+  public StructureCommandI openSession(String filepath)
+  {
+    // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html#composite
+    // this version of the command has no dependency on file extension
+    return new StructureCommand("open " + filepath + " format session");
+  }
+
+  @Override
+  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 jalview prefix ModelChanged 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;
+  }
 }