Merge JAL-2136_phyre2_integration to develop
[jalview.git] / src / jalview / io / AnnotationFile.java
index eca27a7..b72184b 100755 (executable)
@@ -32,15 +32,16 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.gui.Desktop;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.UserColourScheme;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.ColorUtils;
 
+import java.awt.Color;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
-import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.StringReader;
 import java.net.URL;
@@ -586,7 +587,7 @@ public class AnnotationFile
       if (sg.cs != null)
       {
         text.append("colour=");
-        text.append(ColourSchemeProperty.getColourName(sg.cs));
+        text.append(sg.cs.toString());
         text.append("\t");
         if (sg.cs.getThreshold() != 0)
         {
@@ -665,7 +666,7 @@ public class AnnotationFile
   String refSeqId = null;
 
   public boolean annotateAlignmentView(AlignViewportI viewport,
-          String file, String protocol)
+          String file, DataSourceType protocol)
   {
     ColumnSelection colSel = viewport.getColumnSelection();
     if (colSel == null)
@@ -683,19 +684,19 @@ public class AnnotationFile
   }
 
   public boolean readAnnotationFile(AlignmentI al, String file,
-          String protocol)
+          DataSourceType sourceType)
   {
-    return readAnnotationFile(al, null, file, protocol);
+    return readAnnotationFile(al, null, file, sourceType);
   }
 
   public boolean readAnnotationFile(AlignmentI al, ColumnSelection colSel,
-          String file, String protocol)
+          String file, DataSourceType sourceType)
   {
     baseUri = "";
     BufferedReader in = null;
     try
     {
-      if (protocol.equals(AppletFormatAdapter.FILE))
+      if (sourceType == DataSourceType.FILE)
       {
         in = new BufferedReader(new FileReader(file));
         baseUri = new File(file).getParent();
@@ -708,7 +709,7 @@ public class AnnotationFile
           baseUri += "/";
         }
       }
-      else if (protocol.equals(AppletFormatAdapter.URL))
+      else if (sourceType == DataSourceType.URL)
       {
         URL url = new URL(file);
         in = new BufferedReader(new InputStreamReader(url.openStream()));
@@ -721,13 +722,13 @@ public class AnnotationFile
           baseUri = baseUri.substring(0, baseUri.lastIndexOf("/")) + "/";
         }
       }
-      else if (protocol.equals(AppletFormatAdapter.PASTE))
+      else if (sourceType == DataSourceType.PASTE)
       {
         in = new BufferedReader(new StringReader(file));
         // TODO - support mimencoded PDBs for a paste.. ?
         baseUri = "";
       }
-      else if (protocol.equals(AppletFormatAdapter.CLASSLOADER))
+      else if (sourceType == DataSourceType.CLASSLOADER)
       {
         java.io.InputStream is = getClass().getResourceAsStream("/" + file);
         if (is != null)
@@ -1017,8 +1018,11 @@ public class AnnotationFile
         {
           boolean failedtoadd = true;
           // expect
-          // STRUCTMODEL <QUERYID> <TemplateID> <URL to model> <URL to
-          // alignment>
+          // STRUCTMODEL <Query> <TemplateSeqId> <ModelFile> <FastaMappingFile>
+          // <Confidence> <%.I.D>
+          // <MatchStart> <MatchEnd> <Coverage> [<Other Information>]
+          String querySeqId = !st.hasMoreTokens() ? "" : st.nextToken();
+          SequenceI querySeq = al.findName(querySeqId);
           if (st.hasMoreTokens()) {
             refSeq = al.findName(refSeqId = st.nextToken());
             if (refSeq == null)
@@ -1030,11 +1034,18 @@ public class AnnotationFile
             else
             {
               String tempId = st.nextToken();
-              String urlToModel = st.nextToken();
-              String urlToPairwise = st.hasMoreTokens() ? st.nextToken()
-                      : "";
-              if (add_structmodel(al, refSeq, tempId, urlToModel,
-                      urlToPairwise))
+              String fastaMapping = st.nextToken();
+              String confidence = !st.hasMoreTokens() ? "" : 100
+                      * Double.valueOf(st.nextToken()) + "";
+              String pid = !st.hasMoreTokens() ? "" : st.nextToken();
+              String alignRange = !st.hasMoreTokens() ? "" : st.nextToken()
+                      + "-" + st.nextToken();
+              String otherInfo = !st.hasMoreTokens() ? "" : st.nextToken();
+              String coverage = "";
+              if (add_structmodel(al, querySeq, refSeq, tempId,
+                      fastaMapping,
+                      alignRange, coverage,
+                      confidence, pid, otherInfo))
               {
                 failedtoadd = false;
               }
@@ -1043,8 +1054,9 @@ public class AnnotationFile
           if (failedtoadd)
           {
             System.err
-                    .println("Need <QueryId> <TemplateId> <URL to Model> [<URL to pairwise alignment>] as tab separated fields after "
-                            + STRUCTMODEL);
+                    .println("Need <Query> <TemplateSeqId> <ModelFile> <FastaMappingFile> <Confidence> <%.I.D> <MatchStart> <MatchEnd> <Coverage> [<Other Information>] as tab separated fields after"
+                            + STRUCTMODEL
+                            + ".\nNote: other information could be provided in html format ");
           } else {
             modified = true;
           }
@@ -1259,76 +1271,36 @@ public class AnnotationFile
    * @param urlToPairwise
    * @return true if model and sequence was added
    */
-  private boolean add_structmodel(AlignmentI al, SequenceI refSeq2, String tempId,
-          String urlToModel, String urlToPairwise)
+  private boolean add_structmodel(AlignmentI al, SequenceI querySequence,
+          SequenceI templateSeq,
+          String modelFile, String fastaFile, String aRange,
+          String coverage, String confidence,
+          String pid, String otherInfo)
   {
-    String warningMessage = null, modelPath = null, modelProt = null, aliPath = null, aliProt = null;
+    String warningMessage = null;
     boolean added = false;
     try {
-      // locate tempId. if it exists, will need to merge, otherwise:
-      SequenceI templateSeq = al.findName(tempId);
-      // 1. load urlToModel
-      modelPath = resolveAbsolute(urlToModel);
-      modelProt = AppletFormatAdapter.checkProtocol(modelPath);
-      // need to transfer to local temp file ?
-      PDBEntry modelpe = new PDBEntry(tempId, null, Type.FILE, modelPath);
-      PDBEntry templpe = new PDBEntry(tempId, null, Type.FILE, modelPath);
-      refSeq2.addPDBId(modelpe);
-      aliPath = resolveAbsolute(urlToPairwise);
-      aliProt = AppletFormatAdapter.checkProtocol(aliPath);
-      // 2. load urlToPairwise
-      AlignmentI pwa = new AppletFormatAdapter().readFile(aliPath, aliProt,
-              "FASTA");
-      SequenceI qPw = null, tPw = null;
-      if (pwa != null)
-      {
-        // resolve query/template sequences in provided alignment
-        qPw = pwa.findName(refSeqId);
-        tPw = pwa.findName(tempId);
-      }
-      if (false)
-      // (qPw != null && tPw != null)
-      {
-        // not yet complete
-        // refalQ vvva--addrvvvtttddd
-        // refalT ---aaaa---sss---ddd
-        // profalQ ---v-v-v-a.-.-a---dd--r--vvvtt--td--dd
-        // profalT ---.-.-.-aa-a-a---..--.--sss..--.d--dd
-        // Pragmatic solution here:
-        // Map templpe onto refalT only where refalT and refalQ are both
-        // non-gaps
-
-        // columns for start..end in refSeq2
-        int[] gapMap = refSeq2.gapMap();
-        // insert gaps in tPw
-        int curi = 0, width = refSeq2.getLength();
-        // TBC
-      }
-      else
-      {
-        // assume 1:1 - so synthesise sequences to use to construct mapping
-        StructureFile pdbf = StructureSelectionManager
-                .getStructureSelectionManager().setMapping(false,
-                        new SequenceI[] { refSeq2.getDatasetSequence() },
-                        null, modelPath, modelProt);
-        refSeq2.getDatasetSequence().addPDBId(modelpe);
-        if (templateSeq == null && tPw != null)
-        {
-          tPw.createDatasetSequence();
-          tPw.getDatasetSequence().addPDBId(templpe); // needs to set mapping based on model yet...
-          al.addSequence(tPw);
-          added = true;
-        }
-      }
-    // 3. pad/insert gaps in urlToPairwise according to gaps already present in
-    // refSeq2
-    // 4. add padded tempId sequence to alignment
-    // 4. associate urlToModel with refSeq2 based on position map provided by
-    // urlToPairwise
-    // 5. associate urlToModel with tempId based on position map provided by
-    // urlToPairwise
-    // start a thread to load urlToModel and process/annotate sequences.
-    } catch (IOException x)
+      String structureModelFile = resolveAbsolute(modelFile);
+      String fastaMappingFile = resolveAbsolute(fastaFile.replaceAll(
+              ".fasta.jal", ".fasta"));
+      // System.out.println("Model File >> " + structureModelFile);
+      // System.out.println("Fasta File >> " + fastaMappingFile);
+      PDBEntry phyre2PDBEntry = new PDBEntry(modelFile, null, Type.FILE,
+              structureModelFile);
+      String phyre2ModelDesc = generatePhyre2InfoHTMLTable(aRange,
+              coverage, confidence, pid, otherInfo);
+      phyre2PDBEntry.setProperty("PHYRE2_MODEL_INFO", phyre2ModelDesc);
+      templateSeq.getDatasetSequence().addPDBId(phyre2PDBEntry);
+      if (querySequence != null)
+      {
+        querySequence.getDatasetSequence().addPDBId(phyre2PDBEntry);
+      }
+      StructureSelectionManager ssm = StructureSelectionManager
+              .getStructureSelectionManager(Desktop.instance);
+      ssm.registerPhyre2Template(structureModelFile, fastaMappingFile);
+      added = true;
+
+    } catch (Exception x)
     {
       warningMessage = x.toString();
     } finally {
@@ -1336,8 +1308,44 @@ public class AnnotationFile
       {
         System.err.println("Warnings whilst processing STRUCTMODEL: "+warningMessage);
       }
-      return added;
     }
+    return added;
+  }
+
+  private String generatePhyre2InfoHTMLTable(String aRange,
+          String coverage, String confidence, String pid, String otherInfo)
+  {
+    StringBuilder phyre2InfoBuilder = new StringBuilder();
+    phyre2InfoBuilder.append("<html><table border=\"1\" width=100%>");
+    phyre2InfoBuilder
+            .append("<tr><td colspan=\"2\"><strong>Phyre2 Template Info</strong></td></tr>");
+    if (aRange != null && !aRange.isEmpty())
+    {
+      phyre2InfoBuilder.append("<tr><td>").append("Aligned range")
+              .append("</td><td>").append(aRange).append("</td></tr>");
+    }
+    if (coverage != null && !coverage.isEmpty())
+    {
+      phyre2InfoBuilder.append("<tr><td>").append("Coverage")
+              .append("</td><td>").append(coverage).append("</td></tr>");
+    }
+    if (confidence != null && !confidence.isEmpty())
+    {
+      phyre2InfoBuilder.append("<tr><td>").append("Confidence")
+              .append("</td><td>").append(confidence).append("</td></tr>");
+    }
+    if (pid != null && !pid.isEmpty())
+    {
+      phyre2InfoBuilder.append("<tr><td>").append("%.i.d")
+              .append("</td><td>").append(pid).append("</td></tr>");
+    }
+    if (otherInfo != null && !otherInfo.isEmpty())
+    {
+      phyre2InfoBuilder.append("<tr><td>").append("Other information")
+              .append("</td><td>").append(otherInfo).append("</td></tr>");
+    }
+    phyre2InfoBuilder.append("</table></html>");
+    return phyre2InfoBuilder.toString();
   }
 
   private String resolveAbsolute(String relURI)
@@ -1394,29 +1402,21 @@ public class AnnotationFile
 
   Annotation parseAnnotation(String string, int graphStyle)
   {
-    boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH); // don't
-    // do the
-    // glyph
-    // test
-    // if we
-    // don't
-    // want
-    // secondary
-    // structure
+    // don't do the glyph test if we don't want secondary structure
+    boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH);
     String desc = null, displayChar = null;
     char ss = ' '; // secondaryStructure
     float value = 0;
     boolean parsedValue = false, dcset = false;
 
     // find colour here
-    java.awt.Color colour = null;
+    Color colour = null;
     int i = string.indexOf("[");
     int j = string.indexOf("]");
     if (i > -1 && j > -1)
     {
-      UserColourScheme ucs = new UserColourScheme();
-
-      colour = ucs.getColourFromString(string.substring(i + 1, j));
+      colour = ColorUtils.parseColourString(string.substring(i + 1,
+              j));
       if (i > 0 && string.charAt(i - 1) == ',')
       {
         // clip the preceding comma as well
@@ -1518,7 +1518,7 @@ public class AnnotationFile
 
   void colourAnnotations(AlignmentI al, String label, String colour)
   {
-    UserColourScheme ucs = new UserColourScheme(colour);
+    Color awtColour = ColorUtils.parseColourString(colour);
     Annotation[] annotations;
     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
     {
@@ -1529,7 +1529,7 @@ public class AnnotationFile
         {
           if (annotations[j] != null)
           {
-            annotations[j].colour = ucs.findColour('A');
+            annotations[j].colour = awtColour;
           }
         }
       }
@@ -1599,15 +1599,22 @@ public class AnnotationFile
           SequenceGroup groupRef)
   {
     String group = st.nextToken();
-    AlignmentAnnotation annotation = null, alannot[] = al
-            .getAlignmentAnnotation();
-    float value = new Float(st.nextToken()).floatValue();
+    AlignmentAnnotation[] alannot = al.getAlignmentAnnotation();
+    String nextToken = st.nextToken();
+    float value = 0f;
+    try
+    {
+      value = Float.valueOf(nextToken);
+    } catch (NumberFormatException e)
+    {
+      System.err.println("line " + nlinesread + ": Threshold '" + nextToken
+              + "' invalid, setting to zero");
+    }
     String label = st.hasMoreTokens() ? st.nextToken() : null;
-    java.awt.Color colour = null;
+    Color colour = null;
     if (st.hasMoreTokens())
     {
-      UserColourScheme ucs = new UserColourScheme(st.nextToken());
-      colour = ucs.findColour('A');
+      colour = ColorUtils.parseColourString(st.nextToken());
     }
     if (alannot != null)
     {
@@ -1621,10 +1628,6 @@ public class AnnotationFile
         }
       }
     }
-    if (annotation == null)
-    {
-      return;
-    }
   }
 
   void addGroup(AlignmentI al, StringTokenizer st)
@@ -1784,8 +1787,7 @@ public class AnnotationFile
     if (sg != null)
     {
       String keyValue, key, value;
-      ColourSchemeI def = sg.cs;
-      sg.cs = null;
+      ColourSchemeI def = sg.getColourScheme();
       while (st.hasMoreTokens())
       {
         keyValue = st.nextToken();
@@ -1798,7 +1800,8 @@ public class AnnotationFile
         }
         else if (key.equalsIgnoreCase("colour"))
         {
-          sg.cs = ColourSchemeProperty.getColour(al, value);
+          sg.cs.setColourScheme(ColourSchemeProperty
+                  .getColourScheme(al, value));
         }
         else if (key.equalsIgnoreCase("pidThreshold"))
         {
@@ -1808,9 +1811,8 @@ public class AnnotationFile
         else if (key.equalsIgnoreCase("consThreshold"))
         {
           sg.cs.setConservationInc(Integer.parseInt(value));
-          Conservation c = new Conservation("Group", 3,
-                  sg.getSequences(null), sg.getStartRes(),
-                  sg.getEndRes() + 1);
+          Conservation c = new Conservation("Group", sg.getSequences(null),
+                  sg.getStartRes(), sg.getEndRes() + 1);
 
           c.calculate();
           c.verdict(false, 25); // TODO: refer to conservation percent threshold
@@ -1820,7 +1822,7 @@ public class AnnotationFile
         }
         else if (key.equalsIgnoreCase("outlineColour"))
         {
-          sg.setOutlineColour(new UserColourScheme(value).findColour('A'));
+          sg.setOutlineColour(ColorUtils.parseColourString(value));
         }
         else if (key.equalsIgnoreCase("displayBoxes"))
         {
@@ -1840,11 +1842,11 @@ public class AnnotationFile
         }
         else if (key.equalsIgnoreCase("textCol1"))
         {
-          sg.textColour = new UserColourScheme(value).findColour('A');
+          sg.textColour = ColorUtils.parseColourString(value);
         }
         else if (key.equalsIgnoreCase("textCol2"))
         {
-          sg.textColour2 = new UserColourScheme(value).findColour('A');
+          sg.textColour2 = ColorUtils.parseColourString(value);
         }
         else if (key.equalsIgnoreCase("textColThreshold"))
         {
@@ -1852,9 +1854,8 @@ public class AnnotationFile
         }
         else if (key.equalsIgnoreCase("idColour"))
         {
-          // consider warning if colour doesn't resolve to a real colour
-          sg.setIdColour((def = new UserColourScheme(value))
-                  .findColour('A'));
+          Color idColour = ColorUtils.parseColourString(value);
+          sg.setIdColour(idColour == null ? Color.black : idColour);
         }
         else if (key.equalsIgnoreCase("hide"))
         {
@@ -1868,9 +1869,9 @@ public class AnnotationFile
         }
         sg.recalcConservation();
       }
-      if (sg.cs == null)
+      if (sg.getColourScheme() == null)
       {
-        sg.cs = def;
+        sg.setColourScheme(def);
       }
     }
   }