JAL-3518 pull up closeViewer() and external viewer process monitor
[jalview.git] / src / jalview / ext / rbvi / chimera / JalviewChimeraBinding.java
index 476a933..bc4eef4 100644 (file)
@@ -37,7 +37,6 @@ import ext.edu.ucsf.rbvi.strucviz2.ChimeraModel;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
 import jalview.api.AlignmentViewPanel;
-import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.PDBEntry;
@@ -49,6 +48,7 @@ import jalview.gui.StructureViewer.ViewerType;
 import jalview.httpserver.AbstractRequestHandler;
 import jalview.io.DataSourceType;
 import jalview.structure.AtomSpec;
+import jalview.structure.AtomSpecModel;
 import jalview.structure.StructureCommand;
 import jalview.structure.StructureCommandI;
 import jalview.structure.StructureSelectionManager;
@@ -60,15 +60,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   public static final String CHIMERA_FEATURE_GROUP = "Chimera";
 
-  // Chimera clause to exclude alternate locations in atom selection
-  private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9";
-
-  private static final boolean debug = false;
-
-  private static final String PHOSPHORUS = "P";
-
-  private static final String ALPHACARBON = "CA";
-
   /*
    * Object through which we talk to Chimera
    */
@@ -86,8 +77,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   String lastHighlightCommand;
 
-  private Thread chimeraMonitor;
-
   /**
    * Open a PDB structure file in Chimera and set up mappings from Jalview.
    * 
@@ -194,37 +183,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * 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
-   * viewer panels in Jalview if the user closes Chimera.
-   */
-  protected void startChimeraProcessMonitor()
-  {
-    final Process p = chimeraManager.getChimeraProcess();
-    chimeraMonitor = new Thread(new Runnable()
-    {
-
-      @Override
-      public void run()
-      {
-        try
-        {
-          p.waitFor();
-          JalviewStructureDisplayI display = getViewer();
-          if (display != null)
-          {
-            display.closeViewer(false);
-          }
-        } catch (InterruptedException e)
-        {
-          // exit thread if Chimera Viewer is closed in Jalview
-        }
-      }
-    });
-    chimeraMonitor.start();
-  }
-
-  /**
    * Start a dedicated HttpServer to listen for Chimera notifications, and tell it
    * to start listening
    */
@@ -245,25 +203,17 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    * Close down the Jalview viewer and listener, and (optionally) the associated
    * Chimera window.
    */
+  @Override
   public void closeViewer(boolean closeChimera)
   {
-    getSsm().removeStructureViewerListener(this, this.getStructureFiles());
-    if (closeChimera)
-    {
-      chimeraManager.exitChimera();
-    }
+    super.closeViewer(closeChimera);
     if (this.chimeraListener != null)
     {
       chimeraListener.shutdown();
       chimeraListener = null;
     }
+    chimeraManager.clearOnChimeraExit();
     chimeraManager = null;
-
-    if (chimeraMonitor != null)
-    {
-      chimeraMonitor.interrupt();
-    }
-    releaseUIResources();
   }
 
   /**
@@ -314,7 +264,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     boolean launched = chimeraManager.launchChimera(getChimeraPaths());
     if (launched)
     {
-      startChimeraProcessMonitor();
+      startExternalViewerMonitor(chimeraManager.getChimeraProcess());
     }
     else
     {
@@ -339,7 +289,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
    * 
    * @return
    */
-  public boolean isChimeraRunning()
+  @Override
+  public boolean isViewerRunning()
   {
     return chimeraManager.isChimeraLaunched();
   }
@@ -367,10 +318,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     if (getResponse)
     {
       reply = lastReply;
-      if (debug)
-      {
-        log("Response from command ('" + cmd + "') was:\n" + lastReply);
-      }
+      Cache.log.debug(
+              "Response from command ('" + cmd + "') was:\n" + lastReply);
     }
 
     return reply;
@@ -509,7 +458,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
         atomSpecs.add(spec);
       } catch (IllegalArgumentException e)
       {
-        System.err.println("Failed to parse atomspec: " + atomSpec);
+        Cache.log.error("Failed to parse atomspec: " + atomSpec);
       }
     }
     return atomSpecs;
@@ -545,56 +494,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * Ask Chimera to save its session to the given file. Returns true if
-   * successful, else false.
-   * 
-   * @param filepath
-   * @return
-   */
-  public boolean saveSession(String filepath)
-  {
-    if (isChimeraRunning())
-    {
-      /*
-       * 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 = getCommandGenerator().saveSession(filepath)
-              .getCommand();
-      List<String> reply = chimeraManager.sendChimeraCommand(command, true);
-      if (reply.contains("Session written"))
-      {
-        return true;
-      }
-      else
-      {
-        Cache.log
-                .error("Error saving Chimera session: " + reply.toString());
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Ask Chimera to open a session file. Returns true if successful, else false.
-   * The filename must have a .py (Chimera) or .cxs (ChimeraX) extension for
-   * this command to work.
-   * 
-   * @param filepath
-   * @return
-   */
-  public boolean openSession(String filepath)
-  {
-    /*
-     * Chimera:  https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/open.html
-     * ChimeraX: https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html
-     */
-    executeCommand(getCommandGenerator().loadFile(filepath), true);
-    // todo: test for failure - how?
-    return true;
-  }
-
-  /**
    * Send a 'show' command for all atoms in the currently selected columns
    * 
    * TODO: pull up to abstract structure viewer interface
@@ -624,7 +523,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   /**
    * Constructs and send commands to Chimera to set attributes on residues for
-   * features visible in Jalview
+   * features visible in Jalview.
+   * <p>
+   * The syntax is: setattr r &lt;attName&gt; &lt;attValue&gt; &lt;atomSpec&gt;
+   * <p>
+   * For example: setattr r jv_chain "Ferredoxin-1, Chloroplastic" #0:94.A
    * 
    * @param avp
    * @return
@@ -632,14 +535,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   public int sendFeaturesToViewer(AlignmentViewPanel avp)
   {
     // TODO refactor as required to pull up to an interface
-    String[] files = getStructureFiles();
-    if (files == null)
-    {
-      return 0;
-    }
 
+    Map<String, Map<Object, AtomSpecModel>> featureValues = buildFeaturesMap(
+            avp);
     List<StructureCommandI> commands = getCommandGenerator()
-            .setAttributesForFeatures(getSsm(), files, getSequence(), avp);
+            .setAttributes(featureValues);
     if (commands.size() > 10)
     {
       sendCommandsByFile(commands);
@@ -875,6 +775,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     return CHIMERA_SESSION_EXTENSION;
   }
 
+  @Override
   public String getHelpURL()
   {
     return "https://www.cgl.ucsf.edu/chimera/docs/UsersGuide";