JAL-1925 update source version in license
[jalview.git] / src / jalview / ext / jmol / PDBFileWithJmol.java
index 962fe3c..8171f9d 100644 (file)
@@ -1,51 +1,50 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
- * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9.0b2)
+ * 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.
+ * 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/>.
+ * 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.ext.jmol;
 
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.io.AlignFile;
+import jalview.io.FileParse;
+import jalview.schemes.ResidueProperties;
+import jalview.util.MessageManager;
+
 import java.io.IOException;
+import java.util.Hashtable;
 import java.util.Map;
 
-import javax.xml.parsers.ParserConfigurationException;
+import javajs.awt.Dimension;
 
 import org.jmol.api.JmolStatusListener;
 import org.jmol.api.JmolViewer;
-import org.jmol.constant.EnumCallback;
-import org.jmol.constant.EnumStructure;
-import org.jmol.modelset.Chain;
+import org.jmol.c.CBK;
 import org.jmol.modelset.Group;
 import org.jmol.modelset.Model;
 import org.jmol.modelset.ModelSet;
-import org.jmol.modelset.Polymer;
+import org.jmol.modelsetbio.BioModel;
 import org.jmol.modelsetbio.BioPolymer;
 import org.jmol.viewer.Viewer;
-import org.openscience.jmol.app.JmolApp;
-import org.xml.sax.SAXException;
-
-import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
-import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed;
-import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied;
-import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceI;
-import jalview.io.AlignFile;
 
 /**
  * Import and process PDB files with Jmol
@@ -56,23 +55,20 @@ import jalview.io.AlignFile;
 public class PDBFileWithJmol extends AlignFile implements
         JmolStatusListener
 {
-
-  JmolApp jmolApp = null;
-
   Viewer viewer = null;
 
-  public PDBFileWithJmol(String inFile, String type)
-          throws ExceptionUnmatchedClosingParentheses, IOException,
-          ExceptionFileFormatOrSyntax, ParserConfigurationException,
-          SAXException, ExceptionPermissionDenied, ExceptionLoadingFailed,
-          InterruptedException
+  public PDBFileWithJmol(String inFile, String type) throws IOException
   {
     super(inFile, type);
   }
 
+  public PDBFileWithJmol(FileParse fp) throws IOException
+  {
+    super(fp);
+  }
+
   public PDBFileWithJmol()
   {
-    // TODO Auto-generated constructor stub
   }
 
   /**
@@ -83,26 +79,16 @@ public class PDBFileWithJmol extends AlignFile implements
   private Viewer getJmolData()
   {
     if (viewer == null)
-    { // note that -o -n -x are all implied
-      jmolApp = new JmolApp();
-      jmolApp.isDataOnly = true;
-      jmolApp.haveConsole = false;
-      jmolApp.haveDisplay = false;
-      jmolApp.exitUponCompletion = true;
+    {
       try
       {
         viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
-                null, jmolApp.commandOptions, this);
-        viewer.setScreenDimension(jmolApp.startupWidth,
-                jmolApp.startupHeight);
-        jmolApp.startViewer(viewer, null);
+                null, "-x -o -n", this);
       } catch (ClassCastException x)
       {
-        throw new Error(
-                "Jmol version "
-                        + JmolViewer.getJmolVersion()
-                        + " is not compatible with this version of Jalview. Report this problem at issues.jalview.org",
-                x);
+        throw new Error(MessageManager.formatMessage(
+                "error.jmol_version_not_compatible_with_jalview_version",
+                new String[] { JmolViewer.getJmolVersion() }), x);
       }
     }
     return viewer;
@@ -128,120 +114,172 @@ public class PDBFileWithJmol extends AlignFile implements
    * @see jalview.io.AlignFile#parse()
    */
   @Override
-  public void parse() throws IOException, ExceptionFileFormatOrSyntax,
-          ParserConfigurationException, SAXException,
-          ExceptionPermissionDenied, ExceptionLoadingFailed,
-          InterruptedException, ExceptionUnmatchedClosingParentheses
+  public void parse() throws IOException
   {
     Viewer jmd = getJmolData();
     jmd.openReader(getDataName(), getDataName(), getReader());
     waitForScript(jmd);
-    if (jmd.getModelCount() > 0)
+
+    if (jmd.ms.mc > 0)
     {
-      ModelSet ms = jmd.getModelSet();
-      String structs = ms.calculateStructures(null, true, false, true);
+      ModelSet ms = jmd.ms;
+      // Jmol 14.2 added third argument doReport = false
+      ms.calculateStructures(null, true, false, false, true);
       // System.out.println("Structs\n"+structs);
-      for (Model model : ms.getModels())
+      Group group = null;
+      int modelIndex = -1;
+      for (Model model : ms.am)
       {
-        for (int _bp = 0, _bpc = model.getBioPolymerCount(); _bp < _bpc; _bp++)
+        modelIndex++;
+        for (BioPolymer bp : ((BioModel) model).bioPolymers)
         {
-          Polymer bp = model.getBioPolymer(_bp);
-          if (bp instanceof BioPolymer)
+          int lastChainId = 0; // int value of character e.g. 65 for A
+          String lastChainIdAlpha = "";
+
+          int[] groups = bp.getLeadAtomIndices();
+          char seq[] = new char[groups.length], secstr[] = new char[groups.length], secstrcode[] = new char[groups.length];
+          int groupc = 0, len = 0, firstrnum = 1, lastrnum = 0;
+
+          do
           {
-            BioPolymer biopoly = (BioPolymer) bp;
-            char _lastChainId = 0;
-            int[] groups = biopoly.getLeadAtomIndices();
-            Group[] bpgrp = biopoly.getGroups();
-            char seq[] = new char[groups.length], secstr[] = new char[groups.length], secstrcode[] = new char[groups.length];
-            int groupc = 0, len = 0, firstrnum = 1, lastrnum = 0;
-            do
+            if (groupc >= groups.length
+                    || ms.at[groups[groupc]].group.chain.chainID != lastChainId)
             {
-              if (groupc >= groups.length
-                      || ms.atoms[groups[groupc]].getChainID() != _lastChainId)
+              /*
+               * on change of chain (or at end), construct the sequence and
+               * secondary structure annotation for the last chain
+               */
+              if (len > 0)
               {
-                if (len > 0)
+                boolean isNa = bp.isNucleic();
+                // normalise sequence from Jmol to jalview
+                int[] cinds = isNa ? ResidueProperties.nucleotideIndex
+                        : ResidueProperties.aaIndex;
+                int nonGap = isNa ? ResidueProperties.maxNucleotideIndex
+                        : ResidueProperties.maxProteinIndex;
+                char ngc = 'X';
+                char newseq[] = new char[len];
+                Annotation asecstr[] = new Annotation[len + firstrnum - 1];
+                for (int p = 0; p < len; p++)
                 {
-                  char newseq[] = new char[len];
-                  System.arraycopy(seq, 0, newseq, 0, len);
-                  Annotation asecstr[] = new Annotation[len];
-                  for (int p = 0; p < len; p++)
+                  newseq[p] = cinds[seq[p]] == nonGap ? ngc : seq[p];
+                  if (secstr[p] >= 'A' && secstr[p] <= 'z')
                   {
-                    if (secstr[p] >= 'A' && secstr[p] <= 'z')
+                    try
                     {
                       asecstr[p] = new Annotation("" + secstr[p], null,
                               secstrcode[p], Float.NaN);
+                    } catch (ArrayIndexOutOfBoundsException e)
+                    {
+                      // skip - patch for JAL-1836
                     }
                   }
-                  SequenceI sq = new Sequence("" + getDataName() + "|"
-                          + model.getModelTitle() + "|" + _lastChainId,
-                          newseq, firstrnum, lastrnum);
-                  PDBEntry pdbe = new PDBEntry();
-                  pdbe.setFile(getDataName());
-                  pdbe.setId(getDataName());
-                  sq.addPDBId(pdbe);
-                  seqs.add(sq);
-                  if (!(biopoly.isDna() || biopoly.isRna()))
+                }
+                String modelTitle = (String) ms
+                        .getInfo(modelIndex, "title");
+                SequenceI sq = new Sequence("" + getDataName() + "|"
+                        + modelTitle + "|" + lastChainIdAlpha, newseq,
+                        firstrnum, lastrnum);
+                PDBEntry pdbe = new PDBEntry();
+                pdbe.setFile(getDataName());
+                pdbe.setId(getDataName());
+                pdbe.setProperty(new Hashtable());
+                // pdbe.getProperty().put("CHAIN", "" + _lastChainId);
+                pdbe.setChainCode(lastChainIdAlpha);
+                sq.addPDBId(pdbe);
+                // JAL-1533
+                // Need to put the number of models for this polymer somewhere
+                // for Chimera/others to grab
+                // pdbe.getProperty().put("PDBMODELS", biopoly.)
+                seqs.add(sq);
+                if (!isNa)
+                {
+                  String mt = modelTitle == null ? getDataName()
+                          : modelTitle;
+                  if (lastChainId >= ' ')
                   {
-                    AlignmentAnnotation ann = new AlignmentAnnotation(
-                            "Secondary Structure",
-                            "Secondary Structure from PDB File", asecstr);
-                    sq.addAlignmentAnnotation(ann);
-                    annotations.add(ann);
+                    mt += lastChainIdAlpha;
                   }
+                  AlignmentAnnotation ann = new AlignmentAnnotation(
+                          "Secondary Structure", "Secondary Structure for "
+                                  + mt, asecstr);
+                  ann.belowAlignment = true;
+                  ann.visible = true;
+                  ann.autoCalculated = false;
+                  ann.setCalcId(getClass().getName());
+                  sq.addAlignmentAnnotation(ann);
+                  ann.adjustForAlignment();
+                  ann.validateRangeAndDisplay();
+                  annotations.add(ann);
                 }
-                len = 0;
-                firstrnum = 1;
-                lastrnum = 0;
               }
-              if (groupc < groups.length)
+              len = 0;
+              firstrnum = 1;
+              lastrnum = 0;
+            }
+            if (groupc < groups.length)
+            {
+              group = ms.at[groups[groupc]].group;
+              if (len == 0)
+              {
+                firstrnum = group.getResno();
+                lastChainId = group.chain.chainID;
+                lastChainIdAlpha = group.chain.getIDStr();
+              }
+              else
+              {
+                lastrnum = group.getResno();
+              }
+              seq[len] = group.getGroup1();
+
+              /*
+               * JAL-1828 replace a modified amino acid with its standard
+               * equivalent (e.g. MSE with MET->M) to maximise sequence matching
+               */
+              String threeLetterCode = group.getGroup3();
+              String canonical = ResidueProperties
+                      .getCanonicalAminoAcid(threeLetterCode);
+              if (canonical != null
+                      && !canonical.equalsIgnoreCase(threeLetterCode))
               {
-                if (len == 0)
+                seq[len] = ResidueProperties
+                        .getSingleCharacterCode(canonical);
+              }
+              switch (group.getProteinStructureSubType())
+              {
+              case HELIX310:
+                if (secstr[len] == 0)
                 {
-                  firstrnum = bpgrp[groupc].getResno();
-                  _lastChainId = bpgrp[groupc].getChainID();
+                  secstr[len] = '3';
                 }
-                else
+              case HELIXALPHA:
+                if (secstr[len] == 0)
                 {
-                  lastrnum = bpgrp[groupc].getResno();
+                  secstr[len] = 'H';
                 }
-                seq[len] = bpgrp[groupc].getGroup1();
-                switch (bpgrp[groupc].getProteinStructureSubType())
+              case HELIXPI:
+                if (secstr[len] == 0)
                 {
-                case HELIX_310:
-                  if (secstr[len] == 0)
-                  {
-                    secstr[len] = '3';
-                  }
-                case HELIX_ALPHA:
-                  if (secstr[len] == 0)
-                  {
-                    secstr[len] = 'H';
-                  }
-                case HELIX_PI:
-                  if (secstr[len] == 0)
-                  {
-                    secstr[len] = 'P';
-                  }
-                case HELIX:
-                  if (secstr[len] == 0)
-                  {
-                    secstr[len] = 'H';
-                  }
-                  secstrcode[len] = 'H';
-                  break;
-                case SHEET:
-                  secstr[len] = 'E';
-                  secstrcode[len] = 'E';
-                  break;
-                default:
-                  secstr[len] = 0;
-                  secstrcode[len] = 0;
+                  secstr[len] = 'P';
+                }
+              case HELIX:
+                if (secstr[len] == 0)
+                {
+                  secstr[len] = 'H';
                 }
-                len++;
+                secstrcode[len] = 'H';
+                break;
+              case SHEET:
+                secstr[len] = 'E';
+                secstrcode[len] = 'E';
+                break;
+              default:
+                secstr[len] = 0;
+                secstrcode[len] = 0;
               }
-            } while (groupc++ < groups.length);
-
-          }
+              len++;
+            }
+          } while (groupc++ < groups.length);
         }
       }
 
@@ -288,7 +326,7 @@ public class PDBFileWithJmol extends AlignFile implements
    * System.err.println("Squashed Jmol callback handler error:");
    * e.printStackTrace(); } }
    */
-  public void notifyCallback(EnumCallback type, Object[] data)
+  public void notifyCallback(CBK type, Object[] data)
   {
     String strInfo = (data == null || data[1] == null ? null : data[1]
             .toString());
@@ -304,11 +342,16 @@ public class PDBFileWithJmol extends AlignFile implements
     case MEASURE:
       String mystatus = (String) data[3];
       if (mystatus.indexOf("Picked") >= 0
-              || mystatus.indexOf("Sequence") >= 0) // picking mode
+              || mystatus.indexOf("Sequence") >= 0)
+      {
+        // Picking mode
         sendConsoleMessage(strInfo);
+      }
       else if (mystatus.indexOf("Completed") >= 0)
+      {
         sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
                 strInfo.length() - 1));
+      }
       break;
     case MESSAGE:
       sendConsoleMessage(data == null ? null : strInfo);
@@ -321,13 +364,6 @@ public class PDBFileWithJmol extends AlignFile implements
     }
   }
 
-  private void notifyFileLoaded(String string, String string2,
-          String string3, String string4, int intValue)
-  {
-    // TODO Auto-generated method stub
-
-  }
-
   String lastConsoleEcho = "";
 
   private void sendConsoleEcho(String string)
@@ -356,7 +392,7 @@ public class PDBFileWithJmol extends AlignFile implements
   }
 
   @Override
-  public boolean notifyEnabled(EnumCallback callbackPick)
+  public boolean notifyEnabled(CBK callbackPick)
   {
     switch (callbackPick)
     {
@@ -366,16 +402,9 @@ public class PDBFileWithJmol extends AlignFile implements
     case LOADSTRUCT:
     case ERROR:
       return true;
-    case MEASURE:
-    case PICK:
-    case HOVER:
-    case RESIZE:
-    case SYNC:
-    case CLICK:
-    case ANIMFRAME:
-    case MINIMIZATION:
+    default:
+      return false;
     }
-    return false;
   }
 
   @Override
@@ -422,10 +451,15 @@ public class PDBFileWithJmol extends AlignFile implements
   }
 
   @Override
-  public void resizeInnerPanel(String data)
+  public Dimension resizeInnerPanel(String data)
   {
-    // TODO Auto-generated method stub
+    return null;
+  }
 
+  @Override
+  public Map<String, Object> getJSpecViewProperty(String arg0)
+  {
+    return null;
   }
 
 }