JAL-1645 Version-Rel Version 2.9 Year-Rel 2015 Licensing glob
[jalview.git] / src / jalview / io / ModellerDescription.java
index fa6ef6d..a7a1efa 100755 (executable)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
- */\r
-package jalview.io;\r
-\r
-import jalview.datamodel.*;\r
-\r
-public class ModellerDescription\r
-{\r
-  /**\r
-   * Translates between a String containing a set of colon-separated values\r
-   * on a single line, and sequence start/end and other properties.\r
-   * See PIRFile IO for its use.\r
-   */\r
-  final String[] seqTypes =\r
-      {\r
-      "sequence", "structure", "structureX", "structureN"};\r
-  final String[] Fields =\r
-      {\r
-      "objectType", "objectId",\r
-      "startField", "startCode",\r
-      "endField", "endCode",\r
-      "description1", "description2",\r
-      "resolutionField", "tailField"};\r
-  final int TYPE = 0;\r
-  final int LOCALID = 1;\r
-  final int START = 2;\r
-  final int START_CHAIN = 3;\r
-  final int END = 4;\r
-  final int END_CHAIN = 5;\r
-  final int DESCRIPTION1 = 6;\r
-  final int DESCRIPTION2 = 7;\r
-  final int RESOLUTION = 8;\r
-  final int TAIL = 9;\r
-\r
-  /**\r
-   * 0 is free text or empty\r
-   * 1 is something that parses to an integer, or \@\r
-   */\r
-  final int Types[] =\r
-      {\r
-      0, 0, 1, 0, 1, 0, 0, 0, 0, 0\r
-  };\r
-  final char Padding[] =\r
-      {\r
-      ' ', ' ', ' ', '.', ' ', '.', '.', '.', '.', '.'\r
-  };\r
-\r
-  java.util.Hashtable fields = new java.util.Hashtable();\r
-  ModellerDescription()\r
-  {\r
-    fields.put(Fields[TAIL], "");\r
-  }\r
-\r
-  class resCode\r
-  {\r
-    Integer val;\r
-    String field;\r
-    resCode(String f, Integer v)\r
-    {\r
-      val = v;\r
-      field = f;\r
-    }\r
-\r
-    resCode(int v)\r
-    {\r
-      val = new Integer(v);\r
-      field = val.toString();\r
-    }\r
-  };\r
-\r
-  private resCode validResidueCode(String field)\r
-  {\r
-    Integer val = null;\r
-    com.stevesoft.pat.Regex r = new com.stevesoft.pat.Regex(\r
-        "\\s*((([-0-9]+).?)|FIRST|LAST|@)");\r
-\r
-    if (!r.search(field))\r
-    {\r
-      return null; // invalid\r
-    }\r
-    String value = r.stringMatched(3);\r
-    if (value == null)\r
-    {\r
-      value = r.stringMatched(1);\r
-    }\r
-    // jalview.bin.Cache.log.debug("from '" + field + "' matched '" + value +\r
-    //                             "'");\r
-    try\r
-    {\r
-      val = Integer.valueOf(value);\r
-      return new resCode(field, val); // successful numeric extraction\r
-    }\r
-    catch (Exception e)\r
-    {\r
-    }\r
-    return new resCode(field, null);\r
-  }\r
-\r
-  private java.util.Hashtable parseDescription(String desc)\r
-  {\r
-    java.util.Hashtable fields = new java.util.Hashtable();\r
-    java.util.StringTokenizer st = new java.util.StringTokenizer(desc, ":");\r
-    String field;\r
-    int type = -1;\r
-    if (st.countTokens() > 0)\r
-    {\r
-      // parse colon-fields\r
-      int i = 0;\r
-      field = st.nextToken(":");\r
-      do\r
-      {\r
-        if (seqTypes[i].equalsIgnoreCase(field))\r
-        {\r
-          break;\r
-        }\r
-      }\r
-      while (++i < seqTypes.length);\r
-\r
-      if (i < seqTypes.length)\r
-      {\r
-        // valid seqType for modeller\r
-        type = i;\r
-        i = 1; // continue parsing fields\r
-        while (i < TAIL && st.hasMoreTokens())\r
-        {\r
-          if ( (field = st.nextToken(":")) != null)\r
-          {\r
-            // validate residue field value\r
-            if (Types[i] == 1)\r
-            {\r
-              resCode val = validResidueCode(field);\r
-              if (val != null)\r
-              {\r
-                fields.put(new String(Fields[i] + "num"), val);\r
-              }\r
-              else\r
-              {\r
-                //      jalview.bin.Cache.log.debug(\r
-                //           "Ignoring non-Modeller description: invalid integer-like field '" + field + "'");\r
-                type = -1; /* invalid field! - throw the FieldSet away */\r
-              }\r
-              ;\r
-            }\r
-            fields.put(Fields[i++], field);\r
-          }\r
-        }\r
-        if (i == TAIL)\r
-        {\r
-          // slurp remaining fields\r
-          while (st.hasMoreTokens())\r
-          {\r
-            field += ":" + st.nextToken(":");\r
-          }\r
-          fields.put(Fields[TAIL], field);\r
-        }\r
-      }\r
-    }\r
-    if (type == -1)\r
-    {\r
-      // object is not a proper ModellerPIR object\r
-      fields = new java.util.Hashtable();\r
-      fields.put(Fields[TAIL], new String(desc));\r
-    }\r
-    else\r
-    {\r
-      fields.put(Fields[TYPE], seqTypes[type]);\r
-    }\r
-    return fields;\r
-  }\r
-\r
-  ModellerDescription(String desc)\r
-  {\r
-    if (desc == null)\r
-    {\r
-      desc = "";\r
-    }\r
-    fields = parseDescription(desc);\r
-  }\r
-\r
-  void setStartCode(int v)\r
-  {\r
-    resCode r;\r
-    fields.put(Fields[START] + "num", r = new resCode(v));\r
-    fields.put(Fields[START], r.field);\r
-  }\r
-\r
-  void setEndCode(int v)\r
-  {\r
-    resCode r;\r
-    fields.put(Fields[END] + "num", r = new resCode(v));\r
-    fields.put(Fields[END], r.field);\r
-  }\r
-\r
-  /**\r
-   * make a possibly updated modeller field line for the sequence object\r
-   * @param seq SequenceI\r
-   */\r
-  ModellerDescription(SequenceI seq)\r
-  {\r
-\r
-    if (seq.getDescription() != null)\r
-    {\r
-      fields = parseDescription(seq.getDescription());\r
-    }\r
-\r
-    if (isModellerFieldset())\r
-    {\r
-      // Set start and end before we update the type (in the case of a synthesized field set)\r
-      if (getStartNum() != seq.getStart() && getStartCode().val != null)\r
-      {\r
-        setStartCode(seq.getStart());\r
-      }\r
-\r
-      if (getEndNum() != seq.getEnd() && getStartCode().val != null)\r
-      {\r
-        setEndCode(seq.getEnd());\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // synthesize fields\r
-      setStartCode(seq.getStart());\r
-      setEndCode(seq.getEnd());\r
-      fields.put(Fields[LOCALID], seq.getName()); // this may be overwritten below...\r
-      // type - decide based on evidence of PDB database references - this also sets the local reference field\r
-      int t = 0; // sequence\r
-      if (seq.getDatasetSequence() != null &&\r
-          seq.getDatasetSequence().getDBRef() != null)\r
-      {\r
-        jalview.datamodel.DBRefEntry[] dbr = seq.getDatasetSequence().getDBRef();\r
-        int i, j;\r
-        for (i = 0, j = dbr.length; i < j; i++)\r
-        {\r
-          if (dbr[i] != null)\r
-          {\r
-            // JBPNote PDB dbRefEntry needs properties to propagate onto ModellerField\r
-            // JBPNote Need to get info from the user about whether the sequence is the one being modelled, or if it is a template.\r
-            if (dbr[i].getSource().equals(jalview.datamodel.DBRefSource.PDB))\r
-            {\r
-              fields.put(Fields[LOCALID], dbr[i].getAccessionId());\r
-              t = 2;\r
-              break;\r
-            }\r
-          }\r
-        }\r
-      }\r
-      fields.put(Fields[TYPE], seqTypes[t]);\r
-    }\r
-\r
-  }\r
-\r
-  /**\r
-   * Indicate if fields parsed to a modeller-like colon-separated value line\r
-   * @return boolean\r
-   */\r
-  boolean isModellerFieldset()\r
-  {\r
-    return (fields.containsKey(Fields[TYPE]));\r
-  }\r
-\r
-  String getDescriptionLine()\r
-  {\r
-    String desc = "";\r
-    int lastfield = Fields.length - 1;\r
-\r
-    if (isModellerFieldset())\r
-    {\r
-      String value;\r
-      // try to write a minimal modeller field set, so..\r
-\r
-      // find the last valid field in the entry\r
-\r
-      for (; lastfield > 6; lastfield--)\r
-      {\r
-        if (fields.containsKey(Fields[lastfield]))\r
-        {\r
-          break;\r
-        }\r
-      }\r
-\r
-      for (int i = 0; i < lastfield; i++)\r
-      {\r
-        value = (String) fields.get(Fields[i]);\r
-        if (value != null && value.length() > 0)\r
-        {\r
-          desc += ( (String) fields.get(Fields[i])) + ":";\r
-        }\r
-        else\r
-        {\r
-          desc += Padding[i] + ":";\r
-        }\r
-      }\r
-    }\r
-    // just return the last field if no others were defined.\r
-    if (fields.containsKey(Fields[lastfield]))\r
-    {\r
-      desc += (String) fields.get(Fields[lastfield]);\r
-    }\r
-    else\r
-    {\r
-      desc += ".";\r
-    }\r
-    return desc;\r
-  }\r
-\r
-  int getStartNum()\r
-  {\r
-    int start = 0;\r
-    resCode val = getStartCode();\r
-    if (val.val != null)\r
-    {\r
-      return val.val.intValue();\r
-    }\r
-    return start;\r
-  }\r
-\r
-  resCode getStartCode()\r
-  {\r
-    if (isModellerFieldset() && fields.containsKey(Fields[START] + "num"))\r
-    {\r
-      return (resCode) fields.get(Fields[START] + "num");\r
-    }\r
-    return null;\r
-  }\r
-\r
-  resCode getEndCode()\r
-  {\r
-    if (isModellerFieldset() && fields.containsKey(Fields[END] + "num"))\r
-    {\r
-      return (resCode) fields.get(Fields[END] + "num");\r
-    }\r
-    return null;\r
-  }\r
-\r
-  int getEndNum()\r
-  {\r
-    int end = 0;\r
-    resCode val = getEndCode();\r
-    if (val.val != null)\r
-    {\r
-      return val.val.intValue();\r
-    }\r
-    return end;\r
-  }\r
-\r
-  /**\r
-   * returns true if sequence object was modifed with a valid modellerField set\r
-   * @param newSeq SequenceI\r
-   * @return boolean\r
-   */\r
-  boolean updateSequenceI(SequenceI newSeq)\r
-  {\r
-    if (isModellerFieldset())\r
-    {\r
-      if (getStartCode().val != null)\r
-      {\r
-        newSeq.setStart(getStartNum());\r
-      }\r
-      else\r
-      {\r
-        newSeq.setStart(1);\r
-      }\r
-      if (getEndCode().val != null)\r
-      {\r
-        newSeq.setEnd(getEndNum());\r
-      }\r
-      else\r
-      {\r
-        newSeq.setEnd(newSeq.getStart() + newSeq.getLength());\r
-      }\r
-      return true;\r
-    }\r
-    return false;\r
-  }\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
+ * Copyright (C) 2015 The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.io;
+
+import jalview.datamodel.SequenceI;
+
+public class ModellerDescription
+{
+  /**
+   * Translates between a String containing a set of colon-separated values on a
+   * single line, and sequence start/end and other properties. See PIRFile IO
+   * for its use.
+   */
+  final String[] seqTypes = { "sequence", "structure", "structureX",
+      "structureN" };
+
+  final String[] Fields = { "objectType", "objectId", "startField",
+      "startCode", "endField", "endCode", "description1", "description2",
+      "resolutionField", "tailField" };
+
+  final int TYPE = 0;
+
+  final int LOCALID = 1;
+
+  final int START = 2;
+
+  final int START_CHAIN = 3;
+
+  final int END = 4;
+
+  final int END_CHAIN = 5;
+
+  final int DESCRIPTION1 = 6;
+
+  final int DESCRIPTION2 = 7;
+
+  final int RESOLUTION = 8;
+
+  final int TAIL = 9;
+
+  /**
+   * 0 is free text or empty 1 is something that parses to an integer, or \@
+   */
+  final int Types[] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
+
+  final char Padding[] = { ' ', ' ', ' ', '.', ' ', '.', '.', '.', '.', '.' };
+
+  java.util.Hashtable fields = new java.util.Hashtable();
+
+  ModellerDescription()
+  {
+    fields.put(Fields[TAIL], "");
+  }
+
+  class resCode
+  {
+    Integer val;
+
+    String field;
+
+    resCode(String f, Integer v)
+    {
+      val = v;
+      field = f;
+    }
+
+    resCode(int v)
+    {
+      val = new Integer(v);
+      field = val.toString();
+    }
+  };
+
+  private resCode validResidueCode(String field)
+  {
+    Integer val = null;
+    com.stevesoft.pat.Regex r = new com.stevesoft.pat.Regex(
+            "\\s*((([-0-9]+).?)|FIRST|LAST|@)");
+
+    if (!r.search(field))
+    {
+      return null; // invalid
+    }
+    String value = r.stringMatched(3);
+    if (value == null)
+    {
+      value = r.stringMatched(1);
+    }
+    // jalview.bin.Cache.log.debug("from '" + field + "' matched '" + value +
+    // "'");
+    try
+    {
+      val = Integer.valueOf(value);
+      return new resCode(field, val); // successful numeric extraction
+    } catch (Exception e)
+    {
+    }
+    return new resCode(field, null);
+  }
+
+  private java.util.Hashtable parseDescription(String desc)
+  {
+    java.util.Hashtable fields = new java.util.Hashtable();
+    java.util.StringTokenizer st = new java.util.StringTokenizer(desc, ":",
+            true);
+
+    String field;
+    int type = -1;
+    if (st.countTokens() > 0)
+    {
+      // parse colon-fields
+      int i = 0;
+      field = st.nextToken(":");
+      do
+      {
+        if (seqTypes[i].equalsIgnoreCase(field))
+        {
+          break;
+        }
+      } while (++i < seqTypes.length);
+
+      if (i < seqTypes.length)
+      {
+        st.nextToken(); // skip ':'
+        // valid seqType for modeller
+        type = i;
+        i = 1; // continue parsing fields
+        while (i < TAIL && st.hasMoreTokens())
+        {
+          if ((field = st.nextToken(":")) != null)
+          {
+            if (!field.equals(":"))
+            {
+              // validate residue field value
+              if (Types[i] == 1)
+              {
+                resCode val = validResidueCode(field);
+                if (val != null)
+                {
+                  fields.put(new String(Fields[i] + "num"), val);
+                }
+                else
+                {
+                  // jalview.bin.Cache.log.debug(
+                  // "Ignoring non-Modeller description: invalid integer-like
+                  // field '" + field + "'");
+                  type = -1; /* invalid field! - throw the FieldSet away */
+                }
+                ;
+              }
+              fields.put(Fields[i++], field);
+              if (st.hasMoreTokens())
+              {
+                st.nextToken(); // skip token sep.
+              }
+            }
+            else
+            {
+              i++;
+            }
+          }
+        }
+        if (i == TAIL)
+        {
+          // slurp remaining fields
+          while (st.hasMoreTokens())
+          {
+            String tl = st.nextToken(":");
+            field += tl.equals(":") ? tl : (":" + tl);
+          }
+          fields.put(Fields[TAIL], field);
+        }
+      }
+    }
+    if (type == -1)
+    {
+      // object is not a proper ModellerPIR object
+      fields = new java.util.Hashtable();
+      fields.put(Fields[TAIL], new String(desc));
+    }
+    else
+    {
+      fields.put(Fields[TYPE], seqTypes[type]);
+    }
+    return fields;
+  }
+
+  ModellerDescription(String desc)
+  {
+    if (desc == null)
+    {
+      desc = "";
+    }
+    fields = parseDescription(desc);
+  }
+
+  void setStartCode(int v)
+  {
+    resCode r;
+    fields.put(Fields[START] + "num", r = new resCode(v));
+    fields.put(Fields[START], r.field);
+  }
+
+  void setEndCode(int v)
+  {
+    resCode r;
+    fields.put(Fields[END] + "num", r = new resCode(v));
+    fields.put(Fields[END], r.field);
+  }
+
+  /**
+   * make a possibly updated modeller field line for the sequence object
+   * 
+   * @param seq
+   *          SequenceI
+   */
+  ModellerDescription(SequenceI seq)
+  {
+
+    if (seq.getDescription() != null)
+    {
+      fields = parseDescription(seq.getDescription());
+    }
+
+    if (isModellerFieldset())
+    {
+      // Set start and end before we update the type (in the case of a
+      // synthesized field set)
+      if (getStartCode() == null
+              || (getStartNum() != seq.getStart() && getStartCode().val != null))
+      {
+        // unset or user updated sequence start position
+        setStartCode(seq.getStart());
+      }
+
+      if (getEndCode() == null
+              || (getEndNum() != seq.getEnd() && getStartCode() != null && getStartCode().val != null))
+      {
+        setEndCode(seq.getEnd());
+      }
+    }
+    else
+    {
+      // synthesize fields
+      setStartCode(seq.getStart());
+      setEndCode(seq.getEnd());
+      fields.put(Fields[LOCALID], seq.getName()); // this may be overwritten
+      // below...
+      // type - decide based on evidence of PDB database references - this also
+      // sets the local reference field
+      int t = 0; // sequence
+      if (seq.getDatasetSequence() != null
+              && seq.getDatasetSequence().getDBRef() != null)
+      {
+        jalview.datamodel.DBRefEntry[] dbr = seq.getDatasetSequence()
+                .getDBRef();
+        int i, j;
+        for (i = 0, j = dbr.length; i < j; i++)
+        {
+          if (dbr[i] != null)
+          {
+            // JBPNote PDB dbRefEntry needs properties to propagate onto
+            // ModellerField
+            // JBPNote Need to get info from the user about whether the sequence
+            // is the one being modelled, or if it is a template.
+            if (dbr[i].getSource()
+                    .equals(jalview.datamodel.DBRefSource.PDB))
+            {
+              fields.put(Fields[LOCALID], dbr[i].getAccessionId());
+              t = 2;
+              break;
+            }
+          }
+        }
+      }
+      fields.put(Fields[TYPE], seqTypes[t]);
+    }
+
+  }
+
+  /**
+   * Indicate if fields parsed to a modeller-like colon-separated value line
+   * 
+   * @return boolean
+   */
+  boolean isModellerFieldset()
+  {
+    return (fields.containsKey(Fields[TYPE]));
+  }
+
+  String getDescriptionLine()
+  {
+    String desc = "";
+    int lastfield = Fields.length - 1;
+
+    if (isModellerFieldset())
+    {
+      String value;
+      // try to write a minimal modeller field set, so..
+
+      // find the last valid field in the entry
+
+      for (; lastfield > 6; lastfield--)
+      {
+        if (fields.containsKey(Fields[lastfield]))
+        {
+          break;
+        }
+      }
+
+      for (int i = 0; i < lastfield; i++)
+      {
+        value = (String) fields.get(Fields[i]);
+        if (value != null && value.length() > 0)
+        {
+          desc += ((String) fields.get(Fields[i])) + ":";
+        }
+        else
+        {
+          desc += Padding[i] + ":";
+        }
+      }
+    }
+    // just return the last field if no others were defined.
+    if (fields.containsKey(Fields[lastfield]))
+    {
+      desc += (String) fields.get(Fields[lastfield]);
+    }
+    else
+    {
+      desc += ".";
+    }
+    return desc;
+  }
+
+  int getStartNum()
+  {
+    int start = 0;
+    resCode val = getStartCode();
+    if (val != null && val.val != null)
+    {
+      return val.val.intValue();
+    }
+    return start;
+  }
+
+  resCode getStartCode()
+  {
+    if (isModellerFieldset() && fields.containsKey(Fields[START] + "num"))
+    {
+      return (resCode) fields.get(Fields[START] + "num");
+    }
+    return null;
+  }
+
+  resCode getEndCode()
+  {
+    if (isModellerFieldset() && fields.containsKey(Fields[END] + "num"))
+    {
+      return (resCode) fields.get(Fields[END] + "num");
+    }
+    return null;
+  }
+
+  int getEndNum()
+  {
+    int end = 0;
+    resCode val = getEndCode();
+    if (val != null && val.val != null)
+    {
+      return val.val.intValue();
+    }
+    return end;
+  }
+
+  /**
+   * returns true if sequence object was modifed with a valid modellerField set
+   * 
+   * @param newSeq
+   *          SequenceI
+   * @return boolean
+   */
+  boolean updateSequenceI(SequenceI newSeq)
+  {
+    if (isModellerFieldset())
+    {
+      resCode rc = getStartCode();
+      if (rc != null && rc.val != null)
+      {
+        newSeq.setStart(getStartNum());
+      }
+      else
+      {
+        newSeq.setStart(1);
+      }
+      rc = getEndCode();
+      if (rc != null && rc.val != null)
+      {
+        newSeq.setEnd(getEndNum());
+      }
+      else
+      {
+        newSeq.setEnd(newSeq.getStart() + newSeq.getLength());
+      }
+      return true;
+    }
+    return false;
+  }
+}