Merge branch 'features/JAL-2320_closeChimeraAction' into develop
authorJim Procter <jprocter@issues.jalview.org>
Wed, 30 Nov 2016 16:04:57 +0000 (16:04 +0000)
committerJim Procter <jprocter@issues.jalview.org>
Wed, 30 Nov 2016 16:04:57 +0000 (16:04 +0000)
also tidied up javadoc

1  2 
src/ext/edu/ucsf/rbvi/strucviz2/ChimeraManager.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/JalviewChimeraBindingModel.java
src/jalview/structures/models/AAStructureBindingModel.java

@@@ -1,35 -1,3 +1,35 @@@
 +/* vim: set ts=2: */
 +/**
 + * Copyright (c) 2006 The Regents of the University of California.
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + *   1. Redistributions of source code must retain the above copyright
 + *      notice, this list of conditions, and the following disclaimer.
 + *   2. Redistributions in binary form must reproduce the above
 + *      copyright notice, this list of conditions, and the following
 + *      disclaimer in the documentation and/or other materials provided
 + *      with the distribution.
 + *   3. Redistributions must acknowledge that this software was
 + *      originally developed by the UCSF Computer Graphics Laboratory
 + *      under support by the NIH National Center for Research Resources,
 + *      grant P41-RR01081.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + */
  package ext.edu.ucsf.rbvi.strucviz2;
  
  import jalview.ws.HttpClientUtils;
@@@ -380,6 -348,8 +380,8 @@@ public class ChimeraManage
        sendChimeraCommand("stop really", false);
        try
        {
+         // TODO is this too violent? could it force close the process
+         // before it has done an orderly shutdown?
          chimera.destroy();
        } catch (Exception ex)
        {
    {
      return busy;
    }
+   public Process getChimeraProcess()
+   {
+     return chimera;
+   }
  }
@@@ -23,13 -23,13 +23,14 @@@ package jalview.ext.rbvi.chimera
  import jalview.api.AlignmentViewPanel;
  import jalview.api.FeatureRenderer;
  import jalview.api.SequenceRenderer;
+ import jalview.api.structures.JalviewStructureDisplayI;
  import jalview.bin.Cache;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SequenceI;
  import jalview.httpserver.AbstractRequestHandler;
 +import jalview.io.DataSourceType;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ResidueProperties;
  import jalview.structure.AtomSpec;
@@@ -41,7 -41,6 +42,7 @@@ import jalview.util.MessageManager
  import java.awt.Color;
  import java.net.BindException;
  import java.util.ArrayList;
 +import java.util.Hashtable;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
@@@ -65,10 -64,6 +66,10 @@@ public abstract class JalviewChimeraBin
  
    private static final String ALPHACARBON = "CA";
  
 +  private List<String> chainNames = new ArrayList<String>();
 +
 +  private Hashtable<String, String> chainFile = new Hashtable<String, String>();
 +  
    /*
     * Object through which we talk to Chimera
     */
     */
    private long loadNotifiesHandled = 0;
  
+   private Thread chimeraMonitor;
    /**
     * Open a PDB structure file in Chimera and set up mappings from Jalview.
     * 
     * @param ssm
     * @param pdbentry
     * @param sequenceIs
     * @param protocol
     */
    public JalviewChimeraBinding(StructureSelectionManager ssm,
 -          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
 -          String protocol)
 +          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol)
    {
 -    super(ssm, pdbentry, sequenceIs, chains, protocol);
 +    super(ssm, pdbentry, sequenceIs, protocol);
-     viewer = new ChimeraManager(
-             new ext.edu.ucsf.rbvi.strucviz2.StructureManager(true));
+     viewer = new ChimeraManager(new StructureManager(true));
+   }
+   /**
+    * 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 = viewer.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();
    }
  
    /**
      boolean first = true;
      for (String chain : toshow)
      {
 +      int modelNumber = getModelNoForChain(chain);
 +      String showChainCmd = modelNumber == -1 ? "" : modelNumber + ":."
 +              + chain.split(":")[1];
        if (!first)
        {
          cmd.append(",");
        }
 -      cmd.append(":.").append(chain);
 +      cmd.append(showChainCmd);
        first = false;
      }
  
       * window, but it looks more helpful not to (easier to relate chains to the
       * whole)
       */
 -    final String command = "~display #*; ~ribbon #*; ribbon "
 +    final String command = "~display #*; ~ribbon #*; ribbon :"
              + cmd.toString();
      sendChimeraCommand(command, false);
    }
      lastCommand = null;
      viewer = null;
  
+     if (chimeraMonitor != null)
+     {
+       chimeraMonitor.interrupt();
+     }
      releaseUIResources();
    }
  
  
    /**
     * Launch Chimera, unless an instance linked to this object is already
-    * running. Returns true if chimera is successfully launched, or already
+    * running. Returns true if Chimera is successfully launched, or already
     * running, else false.
     * 
     * @return
     */
    public boolean launchChimera()
    {
-     if (!viewer.isChimeraLaunched())
-     {
-       return viewer.launchChimera(StructureManager.getChimeraPaths());
-     }
      if (viewer.isChimeraLaunched())
      {
        return true;
      }
-     log("Failed to launch Chimera!");
-     return false;
+     boolean launched = viewer.launchChimera(StructureManager
+             .getChimeraPaths());
+     if (launched)
+     {
+       startChimeraProcessMonitor();
+     }
+     else
+     {
+       log("Failed to launch Chimera!");
+     }
+     return launched;
    }
  
    /**
      {
        return new String[0];
      }
 -    // if (modelFileNames == null)
 -    // {
 -    // Collection<ChimeraModel> chimodels = viewer.getChimeraModels();
 -    // _modelFileNameMap = new int[chimodels.size()];
 -    // int j = 0;
 -    // for (ChimeraModel chimodel : chimodels)
 -    // {
 -    // String mdlName = chimodel.getModelName();
 -    // }
 -    // modelFileNames = new String[j];
 -    // // System.arraycopy(mset, 0, modelFileNames, 0, j);
 -    // }
  
      return chimeraMaps.keySet().toArray(
              modelFileNames = new String[chimeraMaps.size()]);
    }
  
    /**
--   * Returns a list of chains mapped in this viewer. Note this list is not
--   * currently scoped per structure.
--   * 
--   * @return
--   */
-   /**
 -  public List<String> getChainNames()
 -  {
 -    List<String> names = new ArrayList<String>();
 -    String[][] allNames = getChains();
 -    if (allNames != null)
 -    {
 -      for (String[] chainsForPdb : allNames)
 -      {
 -        if (chainsForPdb != null)
 -        {
 -          for (String chain : chainsForPdb)
 -          {
 -            if (chain != null && !names.contains(chain))
 -            {
 -              names.add(chain);
 -            }
 -          }
 -        }
 -      }
 -    }
 -    return names;
 -  }
 -
 -  /**
     * Send a 'focus' command to Chimera to recentre the visible display
     */
    public void focusView()
        sm.highlightStructure(this, seq, positions);
      }
    }
 +
 +
 +  @Override
 +  public List<String> getChainNames()
 +  {
 +    return chainNames;
 +  }
 +
 +  public Hashtable<String, String> getChainFile()
 +  {
 +    return chainFile;
 +  }
 +
 +  public List<ChimeraModel> getChimeraModelByChain(String chain)
 +  {
 +    return chimeraMaps.get(chainFile.get(chain));
 +  }
 +
 +  public int getModelNoForChain(String chain)
 +  {
 +    List<ChimeraModel> foundModels = getChimeraModelByChain(chain);
 +    if (foundModels != null && !foundModels.isEmpty())
 +    {
 +      return foundModels.get(0).getModelNumber();
 +    }
 +    return -1;
 +  }
  }
  package jalview.gui;
  
  import jalview.api.AlignmentViewPanel;
+ import jalview.api.structures.JalviewStructureDisplayI;
  import jalview.bin.Cache;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SequenceI;
  import jalview.ext.jmol.JalviewJmolBinding;
 +import jalview.io.DataSourceType;
  import jalview.structure.StructureSelectionManager;
  
  import java.awt.Container;
@@@ -42,9 -42,10 +43,9 @@@ public class AppJmolBinding extends Jal
    private FeatureRenderer fr = null;
  
    public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
 -          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
 -          String protocol)
 +          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol)
    {
 -    super(sSm, pdbentry, sequenceIs, chains, protocol);
 +    super(sSm, pdbentry, sequenceIs, protocol);
      appJmolWindow = appJmol;
    }
  
      // TODO Auto-generated method stub
      return null;
    }
+   @Override
+   public JalviewStructureDisplayI getViewer()
+   {
+     return appJmolWindow;
+   }
  }
  package jalview.gui;
  
  import jalview.api.AlignmentViewPanel;
+ import jalview.api.structures.JalviewStructureDisplayI;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SequenceI;
  import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
 +import jalview.io.DataSourceType;
  import jalview.structure.StructureSelectionManager;
  
  public class JalviewChimeraBindingModel extends JalviewChimeraBinding
  
    private FeatureRenderer fr = null;
  
 +
    public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame,
            StructureSelectionManager ssm, PDBEntry[] pdbentry,
 -          SequenceI[][] sequenceIs, String[][] chains, String protocol)
 +          SequenceI[][] sequenceIs, DataSourceType protocol)
    {
 -    super(ssm, pdbentry, sequenceIs, chains, protocol);
 +    super(ssm, pdbentry, sequenceIs, protocol);
      cvf = chimeraViewFrame;
    }
  
  
    }
  
+   @Override
+   public JalviewStructureDisplayI getViewer()
+   {
+     return cvf;
+   }
 -
  }
  package jalview.structures.models;
  
  import jalview.api.StructureSelectionManagerProvider;
+ import jalview.api.structures.JalviewStructureDisplayI;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SequenceI;
 +import jalview.io.DataSourceType;
  import jalview.structure.AtomSpec;
  import jalview.structure.StructureListener;
  import jalview.structure.StructureMapping;
@@@ -71,7 -71,7 +72,7 @@@ public abstract class AAStructureBindin
    /*
     * datasource protocol for access to PDBEntrylatest
     */
 -  String protocol = null;
 +  DataSourceType protocol = null;
  
    protected boolean colourBySequence = true;
  
     * @param protocol
     */
    public AAStructureBindingModel(StructureSelectionManager ssm,
 -          PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
 -          String protocol)
 +          PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
 +          DataSourceType protocol)
    {
      this.ssm = ssm;
      this.sequence = sequenceIs;
      this.nucleotide = Comparison.isNucleotide(sequenceIs);
 -    this.chains = chains;
      this.pdbEntry = pdbentry;
      this.protocol = protocol;
 -    if (chains == null)
 -    {
 -      this.chains = new String[pdbentry.length][];
 -    }
    }
  
    public StructureSelectionManager getSsm()
      return chains;
    }
  
 -  public String getProtocol()
 +  public DataSourceType getProtocol()
    {
      return protocol;
    }
    }
  
    /**
 +   * Returns a list of chains mapped in this viewer.
 +   * 
 +   * @return
 +   */
 +  public abstract List<String> getChainNames();
 +
++  /**
+    * Returns the Jalview panel hosting the structure viewer (if any)
+    * 
+    * @return
+    */
+   public JalviewStructureDisplayI getViewer()
+   {
+     return null;
+   }
  }