Merge branch 'develop' into features/JAL-2295setChimeraAttributes
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 23 Nov 2016 10:03:07 +0000 (10:03 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 23 Nov 2016 10:03:07 +0000 (10:03 +0000)
Conflicts:
src/jalview/structure/StructureSelectionManager.java

1  2 
resources/lang/Messages.properties
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/structure/StructureSelectionManager.java

Simple merge
@@@ -27,9 -27,6 +27,9 @@@ import jalview.bin.Cache
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
  import jalview.datamodel.PDBEntry;
++import jalview.datamodel.SearchResultMatchI;
 +import jalview.datamodel.SearchResults;
- import jalview.datamodel.SearchResults.Match;
 +import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceI;
  import jalview.httpserver.AbstractRequestHandler;
  import jalview.schemes.ColourSchemeI;
@@@ -1080,214 -1098,13 +1080,214 @@@ public abstract class JalviewChimeraBin
      }
    }
  
 +  /**
 +   * Constructs and send commands to Chimera to set attributes on residues for
 +   * features visible in Jalview
 +   * 
 +   * @param avp
 +   */
 +  public void sendFeaturesToViewer(AlignmentViewPanel avp)
 +  {
 +    // TODO refactor as required to pull up to an interface
 +    AlignmentI alignment = avp.getAlignment();
 +    FeatureRenderer fr = getFeatureRenderer(avp);
  
 -  @Override
 -  public List<String> getChainNames()
 +    /*
 +     * fr is null if feature display is turned off
 +     */
 +    if (fr == null)
 +    {
 +      return;
 +    }
 +
 +    String[] files = getPdbFile();
 +    if (files == null)
 +    {
 +      return;
 +    }
 +
 +    StructureMappingcommandSet commandSet = ChimeraCommands
 +            .getSetAttributeCommandsForFeatures(getSsm(), files,
 +                    getSequence(), fr, alignment);
 +    String[] commands = commandSet.commands;
 +    if (commands.length > 10)
 +    {
 +      sendCommandsByFile(commands);
 +    }
 +    else
 +    {
 +      for (String command : commands)
 +      {
 +        sendAsynchronousCommand(command, null);
 +      }
 +    }
 +  }
 +
 +  /**
 +   * Write commands to a temporary file, and send a command to Chimera to open
 +   * the file as a commands script. For use when sending a large number of
 +   * separate commands would overload the REST interface mechanism.
 +   * 
 +   * @param commands
 +   */
 +  protected void sendCommandsByFile(String[] commands)
    {
 -    return chainNames;
 +    try
 +    {
 +      File tmp = File.createTempFile("chim", ".com");
 +      tmp.deleteOnExit();
 +      PrintWriter out = new PrintWriter(new FileOutputStream(tmp));
 +      for (String command : commands)
 +      {
 +        out.println(command);
 +      }
 +      out.flush();
 +      out.close();
 +      String path = tmp.getAbsolutePath();
 +      sendAsynchronousCommand("open cmd:" + path, null);
 +    } catch (IOException e)
 +    {
 +      System.err
 +              .println("Sending commands to Chimera via file failed with "
 +                      + e.getMessage());
 +    }
    }
  
 +  /**
 +   * Get Chimera residues which have the named attribute, find the mapped
 +   * positions in the Jalview sequence(s), and set as sequence features
 +   * 
 +   * @param attName
 +   * @param alignmentPanel
 +   */
 +  public void copyStructureAttributesToFeatures(String attName,
 +          AlignmentViewPanel alignmentPanel)
 +  {
 +    // todo pull up to AAStructureBindingModel (and interface?)
 +
 +    /*
 +     * ask Chimera to list residues with the attribute, reporting its value
 +     */
 +    // 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):
 +
 +    String cmd = "list residues attr '" + attName + "'";
 +    List<String> residues = sendChimeraCommand(cmd, true);
 +
 +    boolean featureAdded = createFeaturesForAttributes(attName, residues);
 +    if (featureAdded)
 +    {
 +      alignmentPanel.getFeatureRenderer().featuresAdded();
 +    }
 +  }
 +
 +  /**
 +   * Create features in Jalview for the given attribute name and structure
 +   * residues.
 +   * 
 +   * <pre>
 +   * The residue list should be 0, 1 or more reply lines of the format: 
 +   *     residue id #0:5.A isHelix -155.000836316 index 5 
 +   * or 
 +   *     residue id #0:6.A isHelix None
 +   * </pre>
 +   * 
 +   * @param attName
 +   * @param residues
 +   * @return
 +   */
 +  protected boolean createFeaturesForAttributes(String attName,
 +          List<String> residues)
 +  {
 +    boolean featureAdded = false;
 +    String featureGroup = getViewerFeatureGroup();
 +
 +    for (String residue : residues)
 +    {
 +      AtomSpec spec = null;
 +      String[] tokens = residue.split(" ");
 +      if (tokens.length < 5)
 +      {
 +        continue;
 +      }
 +      String atomSpec = tokens[2];
 +      String attValue = tokens[4];
 +
 +      /*
 +       * ignore 'None' (e.g. for phi) or 'False' (e.g. for isHelix)
 +       */
 +      if ("None".equalsIgnoreCase(attValue)
 +              || "False".equalsIgnoreCase(attValue))
 +      {
 +        continue;
 +      }
 +
 +      try
 +      {
 +        spec = AtomSpec.fromChimeraAtomspec(atomSpec);
 +      } catch (IllegalArgumentException e)
 +      {
 +        System.err.println("Problem parsing atomspec " + atomSpec);
 +        continue;
 +      }
 +
 +      String chainId = spec.getChain();
 +      String description = attValue;
 +      float score = Float.NaN;
 +      try
 +      {
 +        score = Float.valueOf(attValue);
 +        description = chainId;
 +      } catch (NumberFormatException e)
 +      {
 +        // was not a float value
 +      }
 +
 +      String pdbFile = getPdbFileForModel(spec.getModelNumber());
 +      spec.setPdbFile(pdbFile);
 +
 +      List<AtomSpec> atoms = Collections.singletonList(spec);
 +
 +      /*
 +       * locate the mapped position in the alignment (if any)
 +       */
 +      SearchResults sr = getSsm()
 +              .findAlignmentPositionsForStructurePositions(atoms);
 +
 +      /*
 +       * expect one matched alignment position, or none 
 +       * (if the structure position is not mapped)
 +       */
-       for (Match m : sr.getResults())
++      for (SearchResultMatchI m : sr.getResults())
 +      {
 +        SequenceI seq = m.getSequence();
 +        int start = m.getStart();
 +        int end = m.getEnd();
 +        SequenceFeature sf = new SequenceFeature(attName, description,
 +                start, end, score, featureGroup);
 +        // todo: should SequenceFeature have an explicit property for chain?
 +        // note: repeating the action shouldn't duplicate features
 +        featureAdded |= seq.addSequenceFeature(sf);
 +      }
 +    }
 +    return featureAdded;
 +  }
 +
 +  /**
 +   * Answers the feature group name to apply to features created in Jalview from
 +   * Chimera attributes
 +   * 
 +   * @return
 +   */
 +  protected String getViewerFeatureGroup()
 +  {
 +    // todo pull up to interface
 +    return CHIMERA_FEATURE_GROUP;
 +  }
 +
 +
    public Hashtable<String, String> getChainFile()
    {
      return chainFile;
@@@ -805,28 -806,7 +806,28 @@@ public class StructureSelectionManage
        return;
      }
  
-     SearchResults results = findAlignmentPositionsForStructurePositions(atoms);
 -    SearchResultsI results = new SearchResults();
++    SearchResultsI results = findAlignmentPositionsForStructurePositions(atoms);
 +    for (Object li : listeners)
 +    {
 +      if (li instanceof SequenceListener)
 +      {
 +        ((SequenceListener) li).highlightSequence(results);
 +      }
 +    }
 +  }
 +
 +  /**
 +   * Constructs a SearchResults object holding regions (if any) in the Jalview
 +   * alignment which have a mapping to the structure viewer positions in the
 +   * supplied list
 +   * 
 +   * @param atoms
 +   * @return
 +   */
 +  public SearchResults findAlignmentPositionsForStructurePositions(
 +          List<AtomSpec> atoms)
 +  {
 +    SearchResults results = new SearchResults();
      for (AtomSpec atom : atoms)
      {
        SequenceI lastseq = null;