JAL-1620 version bump and release notes
[jalview.git] / src / jalview / structure / StructureSelectionManager.java
index 4d94b2d..e9aa575 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
  * Copyright (C) 2014 The Jalview Authors
  * 
  * This file is part of Jalview.
@@ -25,13 +25,15 @@ import jalview.api.StructureSelectionManagerProvider;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
 import jalview.util.MessageManager;
 
 import java.io.PrintStream;
 import java.util.Enumeration;
-import java.util.Hashtable;
+import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.Vector;
 
@@ -44,6 +46,70 @@ public class StructureSelectionManager
 
   StructureMapping[] mappings;
 
+  private boolean processSecondaryStructure = false,
+          secStructServices = false, addTempFacAnnot = false;
+
+  /**
+   * @return true if will try to use external services for processing secondary
+   *         structure
+   */
+  public boolean isSecStructServices()
+  {
+    return secStructServices;
+  }
+
+  /**
+   * control use of external services for processing secondary structure
+   * 
+   * @param secStructServices
+   */
+  public void setSecStructServices(boolean secStructServices)
+  {
+    this.secStructServices = secStructServices;
+  }
+
+  /**
+   * flag controlling addition of any kind of structural annotation
+   * 
+   * @return true if temperature factor annotation will be added
+   */
+  public boolean isAddTempFacAnnot()
+  {
+    return addTempFacAnnot;
+  }
+
+  /**
+   * set flag controlling addition of structural annotation
+   * 
+   * @param addTempFacAnnot
+   */
+  public void setAddTempFacAnnot(boolean addTempFacAnnot)
+  {
+    this.addTempFacAnnot = addTempFacAnnot;
+  }
+
+  /**
+   * 
+   * @return if true, the structure manager will attempt to add secondary
+   *         structure lines for unannotated sequences
+   */
+
+  public boolean isProcessSecondaryStructure()
+  {
+    return processSecondaryStructure;
+  }
+
+  /**
+   * Control whether structure manager will try to annotate mapped sequences
+   * with secondary structure from PDB data.
+   * 
+   * @param enable
+   */
+  public void setProcessSecondaryStructure(boolean enable)
+  {
+    processSecondaryStructure = enable;
+  }
+
   /**
    * debug function - write all mappings to stdout
    */
@@ -64,7 +130,36 @@ public class StructureSelectionManager
     }
   }
 
-  Hashtable mappingData = new Hashtable();
+  /**
+   * map between the PDB IDs (or structure identifiers) used by Jalview and the
+   * absolute filenames for PDB data that corresponds to it
+   */
+  HashMap<String, String> pdbIdFileName = new HashMap<String, String>(),
+          pdbFileNameId = new HashMap<String, String>();
+
+  public void registerPDBFile(String idForFile, String absoluteFile)
+  {
+    pdbIdFileName.put(idForFile, absoluteFile);
+    pdbFileNameId.put(absoluteFile, idForFile);
+  }
+
+  public String findIdForPDBFile(String idOrFile)
+  {
+    String id = pdbFileNameId.get(idOrFile);
+    return id;
+  }
+
+  public String findFileForPDBId(String idOrFile)
+  {
+    String id = pdbIdFileName.get(idOrFile);
+    return id;
+  }
+
+  public boolean isPDBFileRegistered(String idOrFile)
+  {
+    return pdbFileNameId.containsKey(idOrFile)
+            || pdbIdFileName.containsKey(idOrFile);
+  }
 
   private static StructureSelectionManager nullProvider = null;
 
@@ -167,9 +262,33 @@ public class StructureSelectionManager
   }
 
   /**
+   * Import structure data and register a structure mapping for broadcasting
+   * colouring, mouseovers and selection events (convenience wrapper).
+   * 
+   * @param sequence
+   *          - one or more sequences to be mapped to pdbFile
+   * @param targetChains
+   *          - optional chain specification for mapping each sequence to pdb
+   *          (may be nill, individual elements may be nill)
+   * @param pdbFile
+   *          - structure data resource
+   * @param protocol
+   *          - how to resolve data from resource
+   * @return null or the structure data parsed as a pdb file
+   */
+  synchronized public MCview.PDBfile setMapping(SequenceI[] sequence,
+          String[] targetChains, String pdbFile, String protocol)
+  {
+    return setMapping(true, sequence, targetChains, pdbFile, protocol);
+  }
+
+  /**
    * create sequence structure mappings between each sequence and the given
    * pdbFile (retrieved via the given protocol).
    * 
+   * @param forStructureView
+   *          when true, record the mapping for use in mouseOvers
+   * 
    * @param sequence
    *          - one or more sequences to be mapped to pdbFile
    * @param targetChains
@@ -181,7 +300,8 @@ public class StructureSelectionManager
    *          - how to resolve data from resource
    * @return null or the structure data parsed as a pdb file
    */
-  synchronized public MCview.PDBfile setMapping(SequenceI[] sequence,
+  synchronized public MCview.PDBfile setMapping(boolean forStructureView,
+          SequenceI[] sequence,
           String[] targetChains, String pdbFile, String protocol)
   {
     /*
@@ -189,26 +309,42 @@ public class StructureSelectionManager
      * the tried and tested MCview pdb mapping
      */
     MCview.PDBfile pdb = null;
-    boolean parseSecStr=true;
-    for (SequenceI sq:sequence)
+    boolean parseSecStr = processSecondaryStructure;
+    if (isPDBFileRegistered(pdbFile))
     {
-      SequenceI ds = sq;while (ds.getDatasetSequence()!=null) { ds = ds.getDatasetSequence();};
-      if (ds.getAnnotation()!=null)
+      for (SequenceI sq : sequence)
       {
-        for (AlignmentAnnotation ala:ds.getAnnotation())
+        SequenceI ds = sq;
+        while (ds.getDatasetSequence() != null)
+        {
+          ds = ds.getDatasetSequence();
+        }
+        ;
+        if (ds.getAnnotation() != null)
         {
-          // false if any annotation present from this structure
-          if (MCview.PDBfile.isCalcIdForFile(ala.getCalcId(), pdbFile))
+          for (AlignmentAnnotation ala : ds.getAnnotation())
           {
-            parseSecStr = false;
+            // false if any annotation present from this structure
+            // JBPNote this fails for jmol/chimera view because the *file* is
+            // passed, not the structure data ID -
+            if (MCview.PDBfile.isCalcIdForFile(ala,
+                    findIdForPDBFile(pdbFile)))
+            {
+              parseSecStr = false;
+            }
           }
         }
       }
     }
     try
     {
-      pdb = new MCview.PDBfile(true, parseSecStr, pdbFile, protocol);
-      
+      pdb = new MCview.PDBfile(addTempFacAnnot, parseSecStr,
+              secStructServices, pdbFile, protocol);
+      if (pdb.id != null && pdb.id.trim().length() > 0
+              && AppletFormatAdapter.FILE.equals(protocol))
+      {
+        registerPDBFile(pdb.id.trim(), pdbFile);
+      }
     } catch (Exception ex)
     {
       ex.printStackTrace();
@@ -253,7 +389,7 @@ public class StructureSelectionManager
       boolean first = true;
       for (int i = 0; i < pdb.chains.size(); i++)
       {
-        PDBChain chain = ((PDBChain) pdb.chains.elementAt(i));
+        PDBChain chain = (pdb.chains.elementAt(i));
         if (targetChain.length() > 0 && !targetChain.equals(chain.id)
                 && !infChain)
         {
@@ -262,8 +398,8 @@ public class StructureSelectionManager
         // TODO: correctly determine sequence type for mixed na/peptide
         // structures
         AlignSeq as = new AlignSeq(sequence[s],
-                ((PDBChain) pdb.chains.elementAt(i)).sequence,
-                ((PDBChain) pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA
+                pdb.chains.elementAt(i).sequence,
+                pdb.chains.elementAt(i).isNa ? AlignSeq.DNA
                         : AlignSeq.PEP);
         as.calcScoreMatrix();
         as.traceAlignment();
@@ -289,11 +425,13 @@ public class StructureSelectionManager
               + maxChain.residues.size() + "\n\n");
       PrintStream ps = new PrintStream(System.out)
       {
+        @Override
         public void print(String x)
         {
           mappingDetails.append(x);
         }
 
+        @Override
         public void println()
         {
           mappingDetails.append("\n");
@@ -309,7 +447,10 @@ public class StructureSelectionManager
               + (maxAlignseq.seq1end + sequence[s].getEnd() - 1));
 
       maxChain.makeExactMapping(maxAlignseq, sequence[s]);
-
+      jalview.datamodel.Mapping sqmpping = maxAlignseq
+              .getMappingFromS1(false);
+      jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping(
+              sqmpping.getMap().getInverse());
       maxChain.transferRESNUMFeatures(sequence[s], null);
 
       // allocate enough slots to store the mapping from positions in
@@ -332,26 +473,30 @@ public class StructureSelectionManager
         index++;
       } while (index < maxChain.atoms.size());
 
-      if (mappings == null)
-      {
-        mappings = new StructureMapping[1];
-      }
-      else
-      {
-        StructureMapping[] tmp = new StructureMapping[mappings.length + 1];
-        System.arraycopy(mappings, 0, tmp, 0, mappings.length);
-        mappings = tmp;
-      }
-
       if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
       {
         pdbFile = "INLINE" + pdb.id;
       }
-
-      mappings[mappings.length - 1] = new StructureMapping(sequence[s],
+      StructureMapping newMapping = new StructureMapping(sequence[s],
               pdbFile, pdb.id, maxChainId, mapping,
               mappingDetails.toString());
-      maxChain.transferResidueAnnotation(mappings[mappings.length - 1]);
+      if (forStructureView)
+      {
+
+        if (mappings == null)
+        {
+          mappings = new StructureMapping[1];
+        }
+        else
+        {
+          StructureMapping[] tmp = new StructureMapping[mappings.length + 1];
+          System.arraycopy(mappings, 0, tmp, 0, mappings.length);
+          mappings = tmp;
+        }
+
+        mappings[mappings.length - 1] = newMapping;
+      }
+      maxChain.transferResidueAnnotation(newMapping, sqmpping);
     }
     // ///////
 
@@ -377,7 +522,6 @@ public class StructureSelectionManager
     {
       return;
     }
-    boolean removeMapping = true;
     String[] handlepdbs;
     Vector pdbs = new Vector();
     for (int i = 0; i < pdbfiles.length; pdbs.addElement(pdbfiles[i++]))
@@ -855,10 +999,10 @@ public class StructureSelectionManager
       listeners.clear();
       listeners = null;
     }
-    if (mappingData != null)
+    if (pdbIdFileName != null)
     {
-      mappingData.clear();
-      mappingData = null;
+      pdbIdFileName.clear();
+      pdbIdFileName = null;
     }
     if (sel_listeners != null)
     {
@@ -902,4 +1046,13 @@ public class StructureSelectionManager
     }
   }
 
+  public void registerPDBEntry(PDBEntry pdbentry)
+  {
+    if (pdbentry.getFile() != null
+            && pdbentry.getFile().trim().length() > 0)
+    {
+      registerPDBFile(pdbentry.getId(), pdbentry.getFile());
+    }
+  }
+
 }