JAL-3518 more pull up / test coverage of structure command generation
[jalview.git] / src / jalview / ext / rbvi / chimera / JalviewChimeraBinding.java
index 9695eae..3656204 100644 (file)
@@ -30,12 +30,11 @@ import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
-import jalview.gui.Preferences;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.httpserver.AbstractRequestHandler;
 import jalview.io.DataSourceType;
 import jalview.structure.AtomSpec;
-import jalview.structure.StructureMappingcommandSet;
+import jalview.structure.StructureCommandsI.SuperposeData;
 import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
@@ -84,7 +83,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   /*
    * Map of ChimeraModel objects keyed by PDB full local file name
    */
-  private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<>();
+  protected Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<>();
 
   String lastHighlightCommand;
 
@@ -127,34 +126,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       if (!alreadyOpen)
       {
         chimeraManager.openModel(file, pe.getId(), ModelType.PDB_MODEL);
-        if (chimeraManager.isChimeraX())
-        {
-          /*
-           * ChimeraX hack: force chimera model name to pdbId
-           */
-          int modelNumber = chimeraMaps.size() + 1;
-          String command = "setattr #" + modelNumber + " models name "
-                  + pe.getId();
-          executeCommand(command, false);
-          modelsToMap.add(new ChimeraModel(pe.getId(), ModelType.PDB_MODEL,
-                  modelNumber, 0));
-        }
-        else
-        {
-          /*
-           * Chimera: query for actual models and find the one with
-           * matching model name - set in viewer.openModel()
-           */
-          List<ChimeraModel> newList = chimeraManager.getModelList();
-          // JAL-1728 newList.removeAll(oldList) does not work
-          for (ChimeraModel cm : newList)
-          {
-            if (cm.getModelName().equals(pe.getId()))
-            {
-              modelsToMap.add(cm);
-            }
-          }
-        }
+        addChimeraModel(pe, modelsToMap);
       }
 
       chimeraMaps.put(file, modelsToMap);
@@ -174,6 +146,31 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
+   * Adds the ChimeraModel corresponding to the given PDBEntry, based on model
+   * name matching PDB id
+   * 
+   * @param pe
+   * @param modelsToMap
+   */
+  protected void addChimeraModel(PDBEntry pe,
+          List<ChimeraModel> modelsToMap)
+  {
+    /*
+     * Chimera: query for actual models and find the one with
+     * matching model name - already set in viewer.openModel()
+     */
+    List<ChimeraModel> newList = chimeraManager.getModelList();
+    // JAL-1728 newList.removeAll(oldList) does not work
+    for (ChimeraModel cm : newList)
+    {
+      if (cm.getModelName().equals(pe.getId()))
+      {
+        modelsToMap.add(cm);
+      }
+    }
+  }
+
+  /**
    * Constructor
    * 
    * @param ssm
@@ -187,11 +184,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   {
     super(ssm, pdbentry, sequenceIs, protocol);
     chimeraManager = new ChimeraManager(new StructureManager(true));
-    String viewerType = Cache.getProperty(Preferences.STRUCTURE_DISPLAY);
-    chimeraManager.setChimeraX(ViewerType.CHIMERAX.name().equals(viewerType));
+    chimeraManager.setChimeraX(ViewerType.CHIMERAX.equals(getViewerType()));
     setStructureCommands(new ChimeraCommands());
   }
 
+  @Override
+  protected ViewerType getViewerType()
+  {
+    return ViewerType.CHIMERA;
+  }
+
   /**
    * Starts a thread that waits for the Chimera process to finish, so that we can
    * then close the associated resources. This avoids leaving orphaned Chimera
@@ -268,10 +270,10 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   /**
    * {@inheritDoc}
    */
-  @Override
   public String superposeStructures(AlignmentI[] _alignment,
           int[] _refStructure, HiddenColumns[] _hiddenCols)
   {
+    // TODO delete method
     StringBuilder allComs = new StringBuilder(128);
     String[] files = getStructureFiles();
 
@@ -312,7 +314,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       SuperposeData[] structures = new SuperposeData[files.length];
       for (int f = 0; f < files.length; f++)
       {
-        structures[f] = new SuperposeData(alignment.getWidth());
+        structures[f] = new SuperposeData(alignment.getWidth(), f);
       }
 
       /*
@@ -522,8 +524,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       }
       else
       {
-        allComs.append("chain @CA|P; ribbon ; focus");
-        allComs.append(selectioncom.toString());
+        allComs.append("chain @CA|P; ribbon ");
+        allComs.append(selectioncom.toString()).append("; focus");
       }
       // allComs.append("; ~display all; chain @CA|P; ribbon ")
       // .append(selectioncom.toString()).append("; focus");
@@ -585,8 +587,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       return true;
     }
 
-    boolean launched = chimeraManager.launchChimera(
-            StructureManager.getChimeraPaths(chimeraManager.isChimeraX()));
+    boolean launched = chimeraManager.launchChimera(getChimeraPaths());
     if (launched)
     {
       startChimeraProcessMonitor();
@@ -599,6 +600,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
+   * Returns a list of candidate paths to the Chimera program executable
+   * 
+   * @return
+   */
+  protected List<String> getChimeraPaths()
+  {
+    return StructureManager.getChimeraPaths(false);
+  }
+
+  /**
    * Answers true if the Chimera process is still running, false if ended or not
    * started.
    * 
@@ -641,16 +652,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * Send a Chimera command asynchronously in a new thread. If the progress
-   * message is not null, display this message while the command is executing.
-   * 
-   * @param command
-   * @param progressMsg
-   */
-  protected abstract void sendAsynchronousCommand(String command,
-          String progressMsg);
-
-  /**
    * @param command
    */
   protected void executeWhenReady(String command)
@@ -856,9 +857,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
        * Chimera:  https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/save.html
        * ChimeraX: https://www.cgl.ucsf.edu/chimerax/docs/user/commands/save.html
        */
-      String command = isChimeraX() ? "save session " : "save ";
-      List<String> reply = chimeraManager.sendChimeraCommand(command + filepath,
-              true);
+      String command = getCommandGenerator().saveSession(filepath);
+      List<String> reply = chimeraManager.sendChimeraCommand(command, true);
       if (reply.contains("Session written"))
       {
         return true;
@@ -935,10 +935,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       return 0;
     }
 
-    StructureMappingcommandSet commandSet = ChimeraCommands
-            .getSetAttributeCommandsForFeatures(getSsm(), files,
-                    getSequence(), avp, chimeraManager.isChimeraX());
-    String[] commands = commandSet.commands;
+    String[] commands = getCommandGenerator()
+            .setAttributesForFeatures(getSsm(), files, getSequence(), avp);
     if (commands.length > 10)
     {
       sendCommandsByFile(commands);
@@ -962,10 +960,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    */
   protected void sendCommandsByFile(String[] commands)
   {
-    boolean toChimeraX = chimeraManager.isChimeraX();
     try
     {
-      File tmp = File.createTempFile("chim", toChimeraX ? ".cxc" : ".com");
+      File tmp = File.createTempFile("chim", getCommandFileExtension());
       tmp.deleteOnExit();
       PrintWriter out = new PrintWriter(new FileOutputStream(tmp));
       for (String command : commands)
@@ -975,7 +972,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       out.flush();
       out.close();
       String path = tmp.getAbsolutePath();
-      String command = "open " + (toChimeraX ? "" : "cmd:") + path;
+      String command = getCommandGenerator().openCommandFile(path);
       sendAsynchronousCommand(command, null);
     } catch (IOException e)
     {
@@ -985,6 +982,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
+   * Returns the file extension required for a file of commands to be read by
+   * the structure viewer
+   * @return
+   */
+  protected String getCommandFileExtension()
+  {
+    return ".com";
+  }
+
+  /**
    * Get Chimera residues which have the named attribute, find the mapped
    * positions in the Jalview sequence(s), and set as sequence features
    * 
@@ -1153,8 +1160,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     return atts;
   }
 
-  public boolean isChimeraX()
+  /**
+   * Returns the file extension to use for a saved viewer session file
+   * 
+   * @return
+   */
+  public String getSessionFileExtension()
+  {
+    return ".py";
+  }
+
+  public String getHelpURL()
   {
-    return chimeraManager.isChimeraX();
+    return "https://www.cgl.ucsf.edu/chimera/docs/UsersGuide";
   }
 }