JAL-1421 generic collections in MCView package (+unit tests)
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 4 Jun 2015 10:07:28 +0000 (11:07 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 4 Jun 2015 10:07:28 +0000 (11:07 +0100)
13 files changed:
src/MCview/AppletPDBCanvas.java
src/MCview/Atom.java
src/MCview/Bond.java
src/MCview/PDBCanvas.java
src/MCview/PDBChain.java
src/MCview/PDBfile.java
src/MCview/Residue.java
src/MCview/Zsort.java
test/MCview/AtomTest.java [new file with mode: 0644]
test/MCview/BondTest.java [new file with mode: 0644]
test/MCview/PDBChainTest.java [new file with mode: 0644]
test/MCview/PDBfileTest.java [new file with mode: 0644]
test/MCview/ResidueTest.java [new file with mode: 0644]

index 211cff0..c1c4b2f 100644 (file)
  */
 package MCview;
 
-import jalview.analysis.AlignSeq;
-import jalview.appletgui.AlignmentPanel;
-import jalview.appletgui.FeatureRenderer;
-import jalview.appletgui.SequenceRenderer;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceI;
-import jalview.structure.AtomSpec;
-import jalview.structure.StructureListener;
-import jalview.structure.StructureMapping;
-import jalview.structure.StructureSelectionManager;
-import jalview.util.MessageManager;
-
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Event;
@@ -49,6 +37,18 @@ import java.io.PrintStream;
 import java.util.List;
 import java.util.Vector;
 
+import jalview.analysis.AlignSeq;
+import jalview.appletgui.AlignmentPanel;
+import jalview.appletgui.FeatureRenderer;
+import jalview.appletgui.SequenceRenderer;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.structure.AtomSpec;
+import jalview.structure.StructureListener;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
+
 public class AppletPDBCanvas extends Panel implements MouseListener,
         MouseMotionListener, StructureListener
 {
@@ -127,7 +127,7 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
   PDBChain mainchain;
 
-  Vector highlightRes;
+  Vector<String> highlightRes;
 
   boolean pdbAction = false;
 
@@ -284,19 +284,19 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     scale = findScale();
   }
 
-  Vector visiblebonds;
+  Vector<Bond> visiblebonds;
 
   void setupBonds()
   {
     seqColoursReady = false;
     // Sort the bonds by z coord
-    visiblebonds = new Vector();
+    visiblebonds = new Vector<Bond>();
 
     for (int ii = 0; ii < pdb.chains.size(); ii++)
     {
       if (pdb.chains.elementAt(ii).isVisible)
       {
-        Vector tmp = pdb.chains.elementAt(ii).bonds;
+        Vector<Bond> tmp = pdb.chains.elementAt(ii).bonds;
 
         for (int i = 0; i < tmp.size(); i++)
         {
@@ -327,12 +327,10 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     {
       if (pdb.chains.elementAt(ii).isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
+        Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
 
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond tmp : bonds)
         {
-          Bond tmp = (Bond) bonds.elementAt(i);
-
           if (tmp.start[0] >= max[0])
           {
             max[0] = tmp.start[0];
@@ -457,20 +455,15 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     {
       if (pdb.chains.elementAt(ii).isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
+        Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
 
         bsize += bonds.size();
 
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond b : bonds)
         {
-          xtot = xtot + ((Bond) bonds.elementAt(i)).start[0]
-                  + ((Bond) bonds.elementAt(i)).end[0];
-
-          ytot = ytot + ((Bond) bonds.elementAt(i)).start[1]
-                  + ((Bond) bonds.elementAt(i)).end[1];
-
-          ztot = ztot + ((Bond) bonds.elementAt(i)).start[2]
-                  + ((Bond) bonds.elementAt(i)).end[2];
+          xtot = xtot + b.start[0] + b.end[0];
+          ytot = ytot + b.start[1] + b.end[1];
+          ztot = ztot + b.start[2] + b.end[2];
         }
       }
     }
@@ -588,7 +581,7 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
         for (int i = 0; i < chain.bonds.size(); i++)
         {
-          Bond tmp = (Bond) chain.bonds.elementAt(i);
+          Bond tmp = chain.bonds.elementAt(i);
           tmp.startCol = Color.lightGray;
           tmp.endCol = Color.lightGray;
           if (chain != mainchain)
@@ -644,13 +637,13 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
         zsort = new Zsort();
       }
 
-      zsort.Zsort(visiblebonds);
+      zsort.sort(visiblebonds);
     }
 
     Bond tmpBond = null;
     for (int i = 0; i < visiblebonds.size(); i++)
     {
-      tmpBond = (Bond) visiblebonds.elementAt(i);
+      tmpBond = visiblebonds.elementAt(i);
 
       xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
       ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
@@ -803,16 +796,18 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
           {
             if (highlightRes == null)
             {
-              highlightRes = new Vector();
+              highlightRes = new Vector<String>();
             }
 
-            if (highlightRes.contains(fatom.alignmentMapping + "" + ""))
+            final String atomString = Integer
+                    .toString(fatom.alignmentMapping);
+            if (highlightRes.contains(atomString))
             {
-              highlightRes.removeElement(fatom.alignmentMapping + "");
+              highlightRes.removeElement(atomString);
             }
             else
             {
-              highlightRes.addElement(fatom.alignmentMapping + "");
+              highlightRes.addElement(atomString);
             }
           }
         }
@@ -901,14 +896,10 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     }
 
     // Alter the bonds
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-      for (int i = 0; i < bonds.size(); i++)
+      for (Bond tmpBond : chain.bonds)
       {
-        Bond tmpBond = (Bond) bonds.elementAt(i);
-
         // Translate the bond so the centre is 0,0,0
         tmpBond.translate(-centre[0], -centre[1], -centre[2]);
 
@@ -942,18 +933,12 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
   void drawLabels(Graphics g)
   {
 
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      PDBChain chain = pdb.chains.elementAt(ii);
-
       if (chain.isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond tmpBond : chain.bonds)
         {
-          Bond tmpBond = (Bond) bonds.elementAt(i);
-
           if (tmpBond.at1.isSelected)
           {
             labelAtom(g, tmpBond, 1);
@@ -961,7 +946,6 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
           if (tmpBond.at2.isSelected)
           {
-
             labelAtom(g, tmpBond, 2);
           }
         }
@@ -1008,11 +992,11 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
       if (chain.isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
+        Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
 
         for (int i = 0; i < bonds.size(); i++)
         {
-          tmpBond = (Bond) bonds.elementAt(i);
+          tmpBond = bonds.elementAt(i);
 
           truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
 
@@ -1077,7 +1061,7 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     Bond tmpBond;
     for (index = 0; index < mainchain.bonds.size(); index++)
     {
-      tmpBond = (Bond) mainchain.bonds.elementAt(index);
+      tmpBond = mainchain.bonds.elementAt(index);
       if (tmpBond.at1.alignmentMapping == ii - 1)
       {
         if (highlightBond1 != null)
@@ -1095,13 +1079,13 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
         if (index > 0)
         {
-          highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
+          highlightBond1 = mainchain.bonds.elementAt(index - 1);
           highlightBond1.at2.isSelected = true;
         }
 
         if (index != mainchain.bonds.size())
         {
-          highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
+          highlightBond2 = mainchain.bonds.elementAt(index);
           highlightBond2.at1.isSelected = true;
         }
 
@@ -1187,7 +1171,7 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     Bond tmpBond;
     for (index = 0; index < mainchain.bonds.size(); index++)
     {
-      tmpBond = (Bond) mainchain.bonds.elementAt(index);
+      tmpBond = mainchain.bonds.elementAt(index);
       if (tmpBond.at1.atomIndex == atomIndex)
       {
         if (highlightBond1 != null)
@@ -1205,13 +1189,13 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
         if (index > 0)
         {
-          highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
+          highlightBond1 = mainchain.bonds.elementAt(index - 1);
           highlightBond1.at2.isSelected = true;
         }
 
         if (index != mainchain.bonds.size())
         {
-          highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
+          highlightBond2 = mainchain.bonds.elementAt(index);
           highlightBond2.at1.isSelected = true;
         }
 
@@ -1243,5 +1227,4 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
     // TODO Auto-generated method stub
 
   }
-
 }
index 9cbcebb..4d000af 100755 (executable)
@@ -111,7 +111,4 @@ public class Atom
     this.y = y;
     this.z = z;
   }
-  // public void setColor(Color col) {
-  // this.color = col;
-  // }
 }
index 18011fb..1f2edd2 100755 (executable)
@@ -20,7 +20,7 @@
  */
 package MCview;
 
-import java.awt.*;
+import java.awt.Color;
 
 public class Bond
 {
@@ -36,10 +36,12 @@ public class Bond
 
   public Atom at2;
 
-  public Bond(float[] start, float[] end, Atom at1, Atom at2)
+  public Bond(Atom at1, Atom at2)
   {
-    this.start = start;
-    this.end = end;
+    this.start = new float[]
+    { at1.x, at1.y, at1.z };
+    this.end = new float[]
+    { at2.x, at2.y, at2.z };
     this.startCol = at1.color;
     this.endCol = at2.color;
     this.at1 = at1;
@@ -70,13 +72,13 @@ public class Bond
 
   public void translate(float x, float y, float z)
   {
-    start[0] = (start[0] + x);
-    end[0] = (end[0] + x);
+    start[0] = start[0] + x;
+    end[0] = end[0] + x;
 
-    start[1] = (start[1] + y);
-    end[1] = (end[1] + y);
+    start[1] = start[1] + y;
+    end[1] = end[1] + y;
 
-    start[2] = (start[2] + z);
-    end[2] = (end[2] + z);
+    start[2] = start[2] + z;
+    end[2] = end[2] + z;
   }
 }
index 6f76a25..76bf59b 100644 (file)
  */
 package MCview;
 
-import jalview.analysis.AlignSeq;
-import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignmentPanel;
-import jalview.gui.FeatureRenderer;
-import jalview.gui.SequenceRenderer;
-import jalview.structure.AtomSpec;
-import jalview.structure.StructureListener;
-import jalview.structure.StructureMapping;
-import jalview.structure.StructureSelectionManager;
-
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Event;
@@ -52,6 +41,17 @@ import java.util.Vector;
 import javax.swing.JPanel;
 import javax.swing.ToolTipManager;
 
+import jalview.analysis.AlignSeq;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.FeatureRenderer;
+import jalview.gui.SequenceRenderer;
+import jalview.structure.AtomSpec;
+import jalview.structure.StructureListener;
+import jalview.structure.StructureMapping;
+import jalview.structure.StructureSelectionManager;
+
 public class PDBCanvas extends JPanel implements MouseListener,
         MouseMotionListener, StructureListener
 {
@@ -123,7 +123,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
   PDBChain mainchain;
 
-  Vector highlightRes;
+  Vector<String> highlightRes;
 
   boolean pdbAction = false;
 
@@ -265,23 +265,21 @@ public class PDBCanvas extends JPanel implements MouseListener,
     ToolTipManager.sharedInstance().setDismissDelay(10000);
   }
 
-  Vector visiblebonds;
+  Vector<Bond> visiblebonds;
 
   void setupBonds()
   {
     seqColoursReady = false;
     // Sort the bonds by z coord
-    visiblebonds = new Vector();
+    visiblebonds = new Vector<Bond>();
 
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      if (pdb.chains.elementAt(ii).isVisible)
+      if (chain.isVisible)
       {
-        Vector tmp = pdb.chains.elementAt(ii).bonds;
-
-        for (int i = 0; i < tmp.size(); i++)
+        for (Bond bond : chain.bonds)
         {
-          visiblebonds.addElement(tmp.elementAt(i));
+          visiblebonds.addElement(bond);
         }
       }
     }
@@ -305,16 +303,12 @@ public class PDBCanvas extends JPanel implements MouseListener,
     min[1] = (float) 1e30;
     min[2] = (float) 1e30;
 
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      if (pdb.chains.elementAt(ii).isVisible)
+      if (chain.isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond tmp : chain.bonds)
         {
-          Bond tmp = (Bond) bonds.elementAt(i);
-
           if (tmp.start[0] >= max[0])
           {
             max[0] = tmp.start[0];
@@ -440,24 +434,17 @@ public class PDBCanvas extends JPanel implements MouseListener,
     int bsize = 0;
 
     // Find centre coordinate
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      if (pdb.chains.elementAt(ii).isVisible)
+      if (chain.isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-        bsize += bonds.size();
+        bsize += chain.bonds.size();
 
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond bond : chain.bonds)
         {
-          xtot = xtot + ((Bond) bonds.elementAt(i)).start[0]
-                  + ((Bond) bonds.elementAt(i)).end[0];
-
-          ytot = ytot + ((Bond) bonds.elementAt(i)).start[1]
-                  + ((Bond) bonds.elementAt(i)).end[1];
-
-          ztot = ztot + ((Bond) bonds.elementAt(i)).start[2]
-                  + ((Bond) bonds.elementAt(i)).end[2];
+          xtot = xtot + bond.start[0] + bond.end[0];
+          ytot = ytot + bond.start[1] + bond.end[1];
+          ztot = ztot + bond.start[2] + bond.end[2];
         }
       }
     }
@@ -562,7 +549,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
         for (int i = 0; i < chain.bonds.size(); i++)
         {
-          Bond tmp = (Bond) chain.bonds.elementAt(i);
+          Bond tmp = chain.bonds.elementAt(i);
           tmp.startCol = Color.lightGray;
           tmp.endCol = Color.lightGray;
           if (chain != mainchain)
@@ -618,13 +605,13 @@ public class PDBCanvas extends JPanel implements MouseListener,
         zsort = new Zsort();
       }
 
-      zsort.Zsort(visiblebonds);
+      zsort.sort(visiblebonds);
     }
 
     Bond tmpBond = null;
     for (int i = 0; i < visiblebonds.size(); i++)
     {
-      tmpBond = (Bond) visiblebonds.elementAt(i);
+      tmpBond = visiblebonds.elementAt(i);
 
       xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getWidth() / 2));
       ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getHeight() / 2));
@@ -779,16 +766,18 @@ public class PDBCanvas extends JPanel implements MouseListener,
           {
             if (highlightRes == null)
             {
-              highlightRes = new Vector();
+              highlightRes = new Vector<String>();
             }
 
-            if (highlightRes.contains(fatom.alignmentMapping + ""))
+            final String atomString = Integer
+                    .toString(fatom.alignmentMapping);
+            if (highlightRes.contains(atomString))
             {
-              highlightRes.remove(fatom.alignmentMapping + "");
+              highlightRes.remove(atomString);
             }
             else
             {
-              highlightRes.add(fatom.alignmentMapping + "");
+              highlightRes.add(atomString);
             }
           }
         }
@@ -870,14 +859,10 @@ public class PDBCanvas extends JPanel implements MouseListener,
     }
 
     // Alter the bonds
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-      for (int i = 0; i < bonds.size(); i++)
+      for (Bond tmpBond : chain.bonds)
       {
-        Bond tmpBond = (Bond) bonds.elementAt(i);
-
         // Translate the bond so the centre is 0,0,0
         tmpBond.translate(-centre[0], -centre[1], -centre[2]);
 
@@ -911,18 +896,12 @@ public class PDBCanvas extends JPanel implements MouseListener,
   void drawLabels(Graphics g)
   {
 
-    for (int ii = 0; ii < pdb.chains.size(); ii++)
+    for (PDBChain chain : pdb.chains)
     {
-      PDBChain chain = pdb.chains.elementAt(ii);
-
       if (chain.isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond tmpBond : chain.bonds)
         {
-          Bond tmpBond = (Bond) bonds.elementAt(i);
-
           if (tmpBond.at1.isSelected)
           {
             labelAtom(g, tmpBond, 1);
@@ -930,7 +909,6 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
           if (tmpBond.at2.isSelected)
           {
-
             labelAtom(g, tmpBond, 2);
           }
         }
@@ -975,11 +953,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
       if (chain.isVisible)
       {
-        Vector bonds = pdb.chains.elementAt(ii).bonds;
-
-        for (int i = 0; i < bonds.size(); i++)
+        for (Bond bond : chain.bonds)
         {
-          tmpBond = (Bond) bonds.elementAt(i);
+          tmpBond = bond;
 
           truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getWidth() / 2));
 
@@ -1015,7 +991,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
       }
 
       if (fatom != null) // )&& chain.ds != null)
-      {
+      { // dead code? value of chain is either overwritten or discarded
         chain = pdb.chains.elementAt(foundchain);
       }
     }
@@ -1041,7 +1017,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
     Bond tmpBond;
     for (index = 0; index < mainchain.bonds.size(); index++)
     {
-      tmpBond = (Bond) mainchain.bonds.elementAt(index);
+      tmpBond = mainchain.bonds.elementAt(index);
       if (tmpBond.at1.alignmentMapping == ii - 1)
       {
         if (highlightBond1 != null)
@@ -1059,13 +1035,13 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
         if (index > 0)
         {
-          highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
+          highlightBond1 = mainchain.bonds.elementAt(index - 1);
           highlightBond1.at2.isSelected = true;
         }
 
         if (index != mainchain.bonds.size())
         {
-          highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
+          highlightBond2 = mainchain.bonds.elementAt(index);
           highlightBond2.at1.isSelected = true;
         }
 
@@ -1153,7 +1129,7 @@ public class PDBCanvas extends JPanel implements MouseListener,
     Bond tmpBond;
     for (index = 0; index < mainchain.bonds.size(); index++)
     {
-      tmpBond = (Bond) mainchain.bonds.elementAt(index);
+      tmpBond = mainchain.bonds.elementAt(index);
       if (tmpBond.at1.atomIndex == atomIndex)
       {
         if (highlightBond1 != null)
@@ -1171,13 +1147,13 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
         if (index > 0)
         {
-          highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
+          highlightBond1 = mainchain.bonds.elementAt(index - 1);
           highlightBond1.at2.isSelected = true;
         }
 
         if (index != mainchain.bonds.size())
         {
-          highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
+          highlightBond2 = mainchain.bonds.elementAt(index);
           highlightBond2.at1.isSelected = true;
         }
 
@@ -1209,5 +1185,4 @@ public class PDBCanvas extends JPanel implements MouseListener,
     // TODO Auto-generated method stub
 
   }
-
 }
index 47ed1ef..0e486ac 100755 (executable)
  */
 package MCview;
 
+import java.awt.Color;
+import java.util.List;
+import java.util.Vector;
+
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
@@ -27,14 +31,10 @@ import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureMapping;
 
-import java.awt.Color;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Vector;
-
 public class PDBChain
 {
   /**
@@ -46,11 +46,11 @@ public class PDBChain
 
   public String id;
 
-  public Vector bonds = new Vector();
+  public Vector<Bond> bonds = new Vector<Bond>();
 
-  public Vector atoms = new Vector();
+  public Vector<Atom> atoms = new Vector<Atom>();
 
-  public Vector residues = new Vector();
+  public Vector<Residue> residues = new Vector<Residue>();
 
   public int offset;
 
@@ -104,16 +104,15 @@ public class PDBChain
 
   public String print()
   {
-    String tmp = "";
+    StringBuilder tmp = new StringBuilder(256);
 
-    for (int i = 0; i < bonds.size(); i++)
+    for (Bond b : bonds)
     {
-      tmp = tmp + ((Bond) bonds.elementAt(i)).at1.resName + " "
-              + ((Bond) bonds.elementAt(i)).at1.resNumber + " " + offset
-              + newline;
+      tmp.append(b.at1.resName).append(" ").append(b.at1.resNumber)
+              .append(" ").append(offset).append(newline);
     }
 
-    return tmp;
+    return tmp.toString();
   }
 
   /**
@@ -129,7 +128,7 @@ public class PDBChain
     int pdbpos = as.getSeq2Start() - 2;
     int alignpos = s1.getStart() + as.getSeq1Start() - 3;
     // first clear out any old alignmentMapping values:
-    for (Atom atom : (Vector<Atom>) atoms)
+    for (Atom atom : atoms)
     {
       atom.alignmentMapping = -1;
     }
@@ -148,11 +147,9 @@ public class PDBChain
 
       if (as.astr1.charAt(i) == as.astr2.charAt(i))
       {
-        Residue res = (Residue) residues.elementAt(pdbpos);
-        Enumeration en = res.atoms.elements();
-        while (en.hasMoreElements())
+        Residue res = residues.elementAt(pdbpos);
+        for (Atom atom : res.atoms)
         {
-          Atom atom = (Atom) en.nextElement();
           atom.alignmentMapping = alignpos;
         }
       }
@@ -196,10 +193,10 @@ public class PDBChain
       if (features[i].getFeatureGroup().equals(pdbid))
       {
         SequenceFeature tx = new SequenceFeature(features[i]);
-        tx.setBegin(1 + ((Atom) ((Residue) residues.elementAt(tx.getBegin()
-                - offset)).atoms.elementAt(0)).alignmentMapping);
-        tx.setEnd(1 + ((Atom) ((Residue) residues.elementAt(tx.getEnd()
-                - offset)).atoms.elementAt(0)).alignmentMapping);
+        tx.setBegin(1 + residues.elementAt(tx.getBegin()
+                - offset).atoms.elementAt(0).alignmentMapping);
+        tx.setEnd(1 + residues.elementAt(tx.getEnd()
+                - offset).atoms.elementAt(0).alignmentMapping);
         tx.setStatus(status
                 + ((tx.getStatus() == null || tx.getStatus().length() == 0) ? ""
                         : ":" + tx.getStatus()));
@@ -212,14 +209,19 @@ public class PDBChain
     return features;
   }
 
+  /**
+   * Traverses the list of residues and constructs bonds where CA-to-CA atoms or
+   * P-to-P atoms are found. Also sets the 'isNa' flag if more than 99% of
+   * residues contain a P not a CA.
+   */
   public void makeCaBondList()
   {
     boolean na = false;
     int numNa = 0;
     for (int i = 0; i < (residues.size() - 1); i++)
     {
-      Residue tmpres = (Residue) residues.elementAt(i);
-      Residue tmpres2 = (Residue) residues.elementAt(i + 1);
+      Residue tmpres = residues.elementAt(i);
+      Residue tmpres2 = residues.elementAt(i + 1);
       Atom at1 = tmpres.findAtom("CA");
       Atom at2 = tmpres2.findAtom("CA");
       na = false;
@@ -245,42 +247,57 @@ public class PDBChain
         System.out.println("not found " + i);
       }
     }
-    if (numNa > 0 && ((numNa / residues.size()) > 0.99))
+
+    /*
+     * If > 99% 'P', flag as nucleotide; note the count doesn't include the last
+     * residue
+     */
+    if (residues.size() > 0 && (numNa / (residues.size() - 1) > 0.99))
     {
       isNa = true;
     }
   }
 
+  /**
+   * Construct a bond from atom1 to atom2 and add it to the list of bonds for
+   * this chain
+   * 
+   * @param at1
+   * @param at2
+   */
   public void makeBond(Atom at1, Atom at2)
   {
-    float[] start = new float[3];
-    float[] end = new float[3];
-
-    start[0] = at1.x;
-    start[1] = at1.y;
-    start[2] = at1.z;
-
-    end[0] = at2.x;
-    end[1] = at2.y;
-    end[2] = at2.z;
-
-    bonds.addElement(new Bond(start, end, at1, at2));
+    bonds.addElement(new Bond(at1, at2));
   }
 
+  /**
+   * Traverses the list of atoms and
+   * <ul>
+   * <li>constructs a list of Residues, each containing all the atoms that share
+   * the same residue number</li>
+   * <li>adds a RESNUM sequence feature for each position</li>
+   * <li>creates the sequence string</li>
+   * <li>determines if nucleotide</li>
+   * <li>saves the residue number of the first atom as 'offset'</li>
+   * <li>adds temp factor annotation if the flag is set to do so</li>
+   * </ul>
+   * 
+   * @param visibleChainAnnotation
+   */
   public void makeResidueList(boolean visibleChainAnnotation)
   {
     int count = 0;
     Object symbol;
     boolean deoxyn = false;
     boolean nucleotide = false;
-    StringBuffer seq = new StringBuffer();
-    Vector resFeatures = new Vector();
-    Vector resAnnotation = new Vector();
+    StringBuilder seq = new StringBuilder(256);
+    Vector<SequenceFeature> resFeatures = new Vector<SequenceFeature>();
+    Vector<Annotation> resAnnotation = new Vector<Annotation>();
     int i, iSize = atoms.size() - 1;
     int resNumber = -1;
     for (i = 0; i <= iSize; i++)
     {
-      Atom tmp = (Atom) atoms.elementAt(i);
+      Atom tmp = atoms.elementAt(i);
       resNumber = tmp.resNumber;
       int res = resNumber;
 
@@ -289,17 +306,17 @@ public class PDBChain
         offset = resNumber;
       }
 
-      Vector resAtoms = new Vector();
+      Vector<Atom> resAtoms = new Vector<Atom>();
       // Add atoms to a vector while the residue number
       // remains the same as the first atom's resNumber (res)
       while ((resNumber == res) && (i < atoms.size()))
       {
-        resAtoms.addElement(atoms.elementAt(i));
+        resAtoms.add(atoms.elementAt(i));
         i++;
 
         if (i < atoms.size())
         {
-          resNumber = ((Atom) atoms.elementAt(i)).resNumber;
+          resNumber = atoms.elementAt(i).resNumber;
         }
         else
         {
@@ -313,8 +330,8 @@ public class PDBChain
       // Make a new Residue object with the new atoms vector
       residues.addElement(new Residue(resAtoms, resNumber - 1, count));
 
-      Residue tmpres = (Residue) residues.lastElement();
-      Atom tmpat = (Atom) tmpres.atoms.elementAt(0);
+      Residue tmpres = residues.lastElement();
+      Atom tmpat = tmpres.atoms.get(0);
       // Make A new SequenceFeature for the current residue numbering
       SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
               + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
@@ -373,8 +390,7 @@ public class PDBChain
     // System.out.println("No of residues = " + residues.size());
     for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
     {
-      sequence.addSequenceFeature((SequenceFeature) resFeatures
-              .elementAt(i));
+      sequence.addSequenceFeature(resFeatures.elementAt(i));
       resFeatures.setElementAt(null, i);
     }
     if (visibleChainAnnotation)
@@ -383,7 +399,7 @@ public class PDBChain
       float max = 0;
       for (i = 0, iSize = annots.length; i < iSize; i++)
       {
-        annots[i] = (Annotation) resAnnotation.elementAt(i);
+        annots[i] = resAnnotation.elementAt(i);
         if (annots[i].value > max)
         {
           max = annots[i].value;
@@ -400,81 +416,74 @@ public class PDBChain
     }
   }
 
+  /**
+   * Colour start/end of bonds by charge
+   * <ul>
+   * <li>ASP and GLU red</li>
+   * <li>LYS and ARG blue</li>
+   * <li>CYS yellow</li>
+   * <li>others light gray</li>
+   * </ul>
+   */
   public void setChargeColours()
   {
-    for (int i = 0; i < bonds.size(); i++)
+    for (Bond b : bonds)
     {
-      try
+      if (b.at1 != null && b.at2 != null)
       {
-        Bond b = (Bond) bonds.elementAt(i);
-
-        if (b.at1.resName.equalsIgnoreCase("ASP")
-                || b.at1.resName.equalsIgnoreCase("GLU"))
-        {
-          b.startCol = Color.red;
-        }
-        else if (b.at1.resName.equalsIgnoreCase("LYS")
-                || b.at1.resName.equalsIgnoreCase("ARG"))
-        {
-          b.startCol = Color.blue;
-        }
-        else if (b.at1.resName.equalsIgnoreCase("CYS"))
-        {
-          b.startCol = Color.yellow;
-        }
-        else
-        {
-          b.startCol = Color.lightGray;
-        }
-
-        if (b.at2.resName.equalsIgnoreCase("ASP")
-                || b.at2.resName.equalsIgnoreCase("GLU"))
-        {
-          b.endCol = Color.red;
-        }
-        else if (b.at2.resName.equalsIgnoreCase("LYS")
-                || b.at2.resName.equalsIgnoreCase("ARG"))
-        {
-          b.endCol = Color.blue;
-        }
-        else if (b.at2.resName.equalsIgnoreCase("CYS"))
-        {
-          b.endCol = Color.yellow;
-        }
-        else
-        {
-          b.endCol = Color.lightGray;
-        }
-      } catch (Exception e)
+        b.startCol = getChargeColour(b.at1.resName);
+        b.endCol = getChargeColour(b.at2.resName);
+      }
+      else
       {
-        Bond b = (Bond) bonds.elementAt(i);
         b.startCol = Color.gray;
         b.endCol = Color.gray;
       }
     }
   }
 
-  public void setChainColours(jalview.schemes.ColourSchemeI cs)
+  public static Color getChargeColour(String resName)
+  {
+    Color result = Color.lightGray;
+    if ("ASP".equals(resName) || "GLU".equals(resName))
+    {
+      result = Color.red;
+    }
+    else if ("LYS".equals(resName) || "ARG".equals(resName))
+    {
+      result = Color.blue;
+    }
+    else if ("CYS".equals(resName))
+    {
+      result = Color.yellow;
+    }
+    return result;
+  }
+
+  /**
+   * Sets the start/end colours of bonds to those of the start/end atoms
+   * according to the specified colour scheme. Note: currently only works for
+   * peptide residues.
+   * 
+   * @param cs
+   */
+  public void setChainColours(ColourSchemeI cs)
   {
-    Bond b;
     int index;
-    for (int i = 0; i < bonds.size(); i++)
+    for (Bond b : bonds)
     {
       try
       {
-        b = (Bond) bonds.elementAt(i);
-
-        index = ((Integer) ResidueProperties.aa3Hash.get(b.at1.resName))
+        index = ResidueProperties.aa3Hash.get(b.at1.resName)
                 .intValue();
         b.startCol = cs.findColour(ResidueProperties.aa[index].charAt(0));
 
-        index = ((Integer) ResidueProperties.aa3Hash.get(b.at2.resName))
+        index = ResidueProperties.aa3Hash.get(b.at2.resName)
                 .intValue();
         b.endCol = cs.findColour(ResidueProperties.aa[index].charAt(0));
 
       } catch (Exception e)
       {
-        b = (Bond) bonds.elementAt(i);
         b.startCol = Color.gray;
         b.endCol = Color.gray;
       }
@@ -483,11 +492,10 @@ public class PDBChain
 
   public void setChainColours(Color col)
   {
-    for (int i = 0; i < bonds.size(); i++)
+    for (Bond b : bonds)
     {
-      Bond tmp = (Bond) bonds.elementAt(i);
-      tmp.startCol = col;
-      tmp.endCol = col;
+      b.startCol = col;
+      b.endCol = col;
     }
   }
 
index 6ca8711..28ece4c 100755 (executable)
  */
 package MCview;
 
+import java.awt.Color;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
 import jalview.analysis.AlignSeq;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
@@ -29,55 +37,58 @@ import jalview.datamodel.SequenceI;
 import jalview.io.FileParse;
 import jalview.util.MessageManager;
 
-import java.awt.Color;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-
 public class PDBfile extends jalview.io.AlignFile
 {
+  private static String CALC_ID_PREFIX = "JalviewPDB";
+
   public Vector<PDBChain> chains;
 
   public String id;
 
   /**
-   * set to true to add chain alignment annotation as visible annotation.
+   * set to true to add derived sequence annotations (temp factor read from
+   * file, or computed secondary structure) to the alignment
    */
-  boolean VisibleChainAnnotation = false;
+  private boolean visibleChainAnnotation = false;
 
-  boolean processSecondaryStructure = true;
+  /*
+   * Set true to predict secondary structure (using JMol for protein, Annotate3D
+   * for RNA)
+   */
+  private boolean predictSecondaryStructure = true;
 
-  boolean externalSecondaryStructure = false;
+  /*
+   * Set true (with predictSecondaryStructure=true) to predict secondary
+   * structure using an external service (currently Annotate3D for RNA only)
+   */
+  private boolean externalSecondaryStructure = false;
 
-  public PDBfile(boolean visibleChainAnnotation,
-          boolean processSecondaryStructure, boolean externalSecStr)
+  public PDBfile(boolean addAlignmentAnnotations, boolean predictSecondaryStructure,
+          boolean externalSecStr)
   {
     super();
-    VisibleChainAnnotation = visibleChainAnnotation;
-    this.processSecondaryStructure = processSecondaryStructure;
+    this.visibleChainAnnotation = addAlignmentAnnotations;
+    this.predictSecondaryStructure = predictSecondaryStructure;
     this.externalSecondaryStructure = externalSecStr;
   }
 
-  public PDBfile(boolean visibleChainAnnotation,
-          boolean processSecondaryStructure, boolean externalSecStr,
-          String file, String protocol) throws IOException
+  public PDBfile(boolean addAlignmentAnnotations, boolean predictSecondaryStructure,
+          boolean externalSecStr, String file, String protocol)
+          throws IOException
   {
     super(false, file, protocol);
-    VisibleChainAnnotation = visibleChainAnnotation;
-    this.processSecondaryStructure = processSecondaryStructure;
+    this.visibleChainAnnotation = addAlignmentAnnotations;
+    this.predictSecondaryStructure = predictSecondaryStructure;
     this.externalSecondaryStructure = externalSecStr;
     doParse();
   }
 
-  public PDBfile(boolean visibleChainAnnotation,
-          boolean processSecondaryStructure, boolean externalSecStr,
-          FileParse source) throws IOException
+  public PDBfile(boolean addAlignmentAnnotations, boolean predictSecondaryStructure,
+          boolean externalSecStr, FileParse source) throws IOException
   {
     super(false, source);
-    VisibleChainAnnotation = visibleChainAnnotation;
-    this.processSecondaryStructure = processSecondaryStructure;
+    this.visibleChainAnnotation = addAlignmentAnnotations;
+    this.predictSecondaryStructure = predictSecondaryStructure;
     this.externalSecondaryStructure = externalSecStr;
     doParse();
   }
@@ -92,15 +103,16 @@ public class PDBfile extends jalview.io.AlignFile
     // TODO set the filename sensibly - try using data source name.
     id = safeName(getDataName());
 
-    chains = new Vector();
-    ArrayList<SequenceI> rna = new ArrayList<SequenceI>(), prot = new ArrayList<SequenceI>();
+    chains = new Vector<PDBChain>();
+    List<SequenceI> rna = new ArrayList<SequenceI>();
+    List<SequenceI> prot = new ArrayList<SequenceI>();
     PDBChain tmpchain;
     String line = null;
     boolean modelFlag = false;
     boolean terFlag = false;
     String lastID = "";
 
-    int index = 0;
+    int indexx = 0;
     String atomnam = null;
     try
     {
@@ -186,34 +198,10 @@ public class PDBfile extends jalview.io.AlignFile
       {
         id = inFile.getName();
       }
-      for (int i = 0; i < chains.size(); i++)
+      for (PDBChain chain : chains)
       {
-        SequenceI dataset = chains.elementAt(i).sequence;
-        dataset.setName(id + "|" + dataset.getName());
-        PDBEntry entry = new PDBEntry();
-        entry.setId(id);
-        entry.setType(PDBEntry.Type.PDB);
-        entry.setProperty(new Hashtable());
-        if (chains.elementAt(i).id != null)
-        {
-          // entry.getProperty().put("CHAIN", chains.elementAt(i).id);
-          entry.setChainCode(String.valueOf(chains.elementAt(i).id));
-        }
-        if (inFile != null)
-        {
-          entry.setFile(inFile.getAbsolutePath());
-        }
-        else
-        {
-          // TODO: decide if we should dump the datasource to disk
-          entry.setFile(getDataName());
-        }
-        dataset.addPDBId(entry);
-        SequenceI chainseq = dataset.deriveSequence(); // PDBChain objects
-        // maintain reference to
-        // dataset
-        seqs.addElement(chainseq);
-        if (isRNA(chainseq) == true)
+        SequenceI chainseq = postProcessChain(chain);
+        if (isRNA(chainseq))
         {
           rna.add(chainseq);
         }
@@ -221,47 +209,10 @@ public class PDBfile extends jalview.io.AlignFile
         {
           prot.add(chainseq);
         }
-
-        AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
-
-        if (chainannot != null && VisibleChainAnnotation)
-        {
-          for (int ai = 0; ai < chainannot.length; ai++)
-          {
-            chainannot[ai].visible = VisibleChainAnnotation;
-            annotations.addElement(chainannot[ai]);
-          }
-        }
       }
-      if (processSecondaryStructure)
+      if (predictSecondaryStructure)
       {
-        if (externalSecondaryStructure && rna.size() > 0)
-        {
-          try
-          {
-            processPdbFileWithAnnotate3d(rna);
-          } catch (Exception x)
-          {
-            System.err
-                    .println("Exceptions when dealing with RNA in pdb file");
-            x.printStackTrace();
-
-          }
-        }
-        ;
-        if (prot.size() > 0)
-        {
-          try
-          {
-            processPdbFileWithJmol(prot);
-          } catch (Exception x)
-          {
-            System.err
-                    .println("Exceptions from Jmol when processing data in pdb file");
-            x.printStackTrace();
-
-          }
-        }
+        predictSecondaryStructure(rna, prot);
       }
     } catch (OutOfMemoryError er)
     {
@@ -280,27 +231,117 @@ public class PDBfile extends jalview.io.AlignFile
     markCalcIds();
   }
 
-  private static String calcIdPrefix = "JalviewPDB";
+  /**
+   * Predict secondary structure for RNA and/or protein sequences and add as
+   * annotations
+   * 
+   * @param rnaSequences
+   * @param proteinSequences
+   */
+  protected void predictSecondaryStructure(List<SequenceI> rnaSequences,
+          List<SequenceI> proteinSequences)
+  {
+    /*
+     * Currently using Annotate3D for RNA, but only if the 'use external
+     * prediction' flag is set
+     */
+    if (externalSecondaryStructure && rnaSequences.size() > 0)
+    {
+      try
+      {
+        processPdbFileWithAnnotate3d(rnaSequences);
+      } catch (Exception x)
+      {
+        System.err
+                .println("Exceptions when dealing with RNA in pdb file");
+        x.printStackTrace();
+
+      }
+    }
+
+    /*
+     * Currently using JMol PDB parser for peptide
+     */
+    if (proteinSequences.size() > 0)
+    {
+      try
+      {
+        processPdbFileWithJmol(proteinSequences);
+      } catch (Exception x)
+      {
+        System.err
+                .println("Exceptions from Jmol when processing data in pdb file");
+        x.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * Process a parsed chain to construct and return a Sequence, and add it to
+   * the list of sequences parsed.
+   * 
+   * @param chain
+   * @return
+   */
+  protected SequenceI postProcessChain(PDBChain chain)
+  {
+    SequenceI dataset = chain.sequence;
+    dataset.setName(id + "|" + dataset.getName());
+    PDBEntry entry = new PDBEntry();
+    entry.setId(id);
+    entry.setType(PDBEntry.Type.PDB);
+    entry.setProperty(new Hashtable());
+    if (chain.id != null)
+    {
+      // entry.getProperty().put("CHAIN", chains.elementAt(i).id);
+      entry.setChainCode(String.valueOf(chain.id));
+    }
+    if (inFile != null)
+    {
+      entry.setFile(inFile.getAbsolutePath());
+    }
+    else
+    {
+      // TODO: decide if we should dump the datasource to disk
+      entry.setFile(getDataName());
+    }
+    dataset.addPDBId(entry);
+    // PDBChain objects maintain reference to dataset
+    SequenceI chainseq = dataset.deriveSequence();
+    seqs.addElement(chainseq);
+
+    AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
+
+    if (chainannot != null && visibleChainAnnotation)
+    {
+      for (int ai = 0; ai < chainannot.length; ai++)
+      {
+        chainannot[ai].visible = visibleChainAnnotation;
+        annotations.addElement(chainannot[ai]);
+      }
+    }
+    return chainseq;
+  }
 
   public static boolean isCalcIdHandled(String calcId)
   {
-    return calcId != null && (calcIdPrefix.equals(calcId));
+    return calcId != null && (CALC_ID_PREFIX.equals(calcId));
   }
 
   public static boolean isCalcIdForFile(AlignmentAnnotation alan,
           String pdbFile)
   {
     return alan.getCalcId() != null
-            && calcIdPrefix.equals(alan.getCalcId())
+            && CALC_ID_PREFIX.equals(alan.getCalcId())
             && pdbFile.equals(alan.getProperty("PDBID"));
   }
 
   public static String relocateCalcId(String calcId,
           Hashtable<String, String> alreadyLoadedPDB) throws Exception
   {
-    int s = calcIdPrefix.length(), end = calcId.indexOf(calcIdPrefix, s);
+    int s = CALC_ID_PREFIX.length(), end = calcId.indexOf(CALC_ID_PREFIX, s);
     String between = calcId.substring(s, end - 1);
-    return calcIdPrefix + alreadyLoadedPDB.get(between) + ":"
+    return CALC_ID_PREFIX + alreadyLoadedPDB.get(between) + ":"
             + calcId.substring(end);
   }
 
@@ -317,7 +358,7 @@ public class PDBfile extends jalview.io.AlignFile
           {
             oldId = "";
           }
-          aa.setCalcId(calcIdPrefix);
+          aa.setCalcId(CALC_ID_PREFIX);
           aa.setProperty("PDBID", id);
           aa.setProperty("oldCalcId", oldId);
         }
@@ -325,7 +366,7 @@ public class PDBfile extends jalview.io.AlignFile
     }
   }
 
-  private void processPdbFileWithJmol(ArrayList<SequenceI> prot)
+  private void processPdbFileWithJmol(List<SequenceI> prot)
           throws Exception
   {
     try
@@ -333,14 +374,16 @@ public class PDBfile extends jalview.io.AlignFile
       Class cl = Class.forName("jalview.ext.jmol.PDBFileWithJmol");
       if (cl != null)
       {
-        Object jmf = cl.getConstructor(new Class[]
-        { FileParse.class }).newInstance(new Object[]
-        { new FileParse(getDataName(), type) });
-        Alignment al = new Alignment((SequenceI[]) cl.getMethod(
+        final Constructor constructor = cl.getConstructor(new Class[]
+        { FileParse.class });
+        final Object[] args = new Object[]
+        { new FileParse(getDataName(), type) };
+        Object jmf = constructor.newInstance(args);
+        AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
                 "getSeqsAsArray", new Class[]
                 {}).invoke(jmf));
         cl.getMethod("addAnnotations", new Class[]
-        { Alignment.class }).invoke(jmf, al);
+        { AlignmentI.class }).invoke(jmf, al);
         for (SequenceI sq : al.getSequences())
         {
           if (sq.getDatasetSequence() != null)
@@ -359,7 +402,7 @@ public class PDBfile extends jalview.io.AlignFile
     }
   }
 
-  private void replaceAndUpdateChains(ArrayList<SequenceI> prot,
+  private void replaceAndUpdateChains(List<SequenceI> prot,
           AlignmentI al, String pep, boolean b)
   {
     List<List<? extends Object>> replaced = AlignSeq
@@ -388,7 +431,7 @@ public class PDBfile extends jalview.io.AlignFile
     }
   }
 
-  private void processPdbFileWithAnnotate3d(ArrayList<SequenceI> rna)
+  private void processPdbFileWithAnnotate3d(List<SequenceI> rna)
           throws Exception
   {
     // System.out.println("this is a PDB format and RNA sequence");
@@ -455,7 +498,7 @@ public class PDBfile extends jalview.io.AlignFile
   {
     for (int i = 0; i < chains.size(); i++)
     {
-      chains.elementAt(i).makeResidueList(VisibleChainAnnotation);
+      chains.elementAt(i).makeResidueList(visibleChainAnnotation);
     }
   }
 
@@ -500,17 +543,17 @@ public class PDBfile extends jalview.io.AlignFile
   {
     for (int i = 0; i < chains.size(); i++)
     {
+      // divide by zero --> infinity --> 255 ;-)
       chains.elementAt(i).setChainColours(
               Color.getHSBColor(1.0f / i, .4f, 1.0f));
     }
   }
 
-  public boolean isRNA(SequenceI seqs)
+  public static boolean isRNA(SequenceI seq)
   {
-    for (int i = 0; i < seqs.getLength(); i++)
+    for (char c : seq.getSequence())
     {
-      if ((seqs.getCharAt(i) != 'A') && (seqs.getCharAt(i) != 'C')
-              && (seqs.getCharAt(i) != 'G') && (seqs.getCharAt(i) != 'U'))
+      if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'U'))
       {
         return false;
       }
index 977323d..abb29a8 100755 (executable)
  */
 package MCview;
 
-import java.util.*;
+import java.util.Vector;
 
 public class Residue
 {
-  Vector atoms = new Vector();
+  Vector<Atom> atoms;
 
   int number;
 
   int count;
 
-  int seqnumber;
-
-  public Residue(Vector atoms, int number, int count)
+  public Residue(Vector<Atom> resAtoms, int number, int count)
   {
-    this.atoms = atoms;
+    this.atoms = resAtoms;
     this.number = number;
     this.count = count;
   }
 
   public Atom findAtom(String name)
   {
-    for (int i = 0; i < atoms.size(); i++)
+    for (Atom atom : atoms)
     {
-      if (((Atom) atoms.elementAt(i)).name.equals(name))
+      if (atom.name.equals(name))
       {
-        return (Atom) atoms.elementAt(i);
+        return atom;
       }
     }
 
index 654eb80..20f034c 100755 (executable)
  */
 package MCview;
 
-import java.util.*;
+import java.util.Vector;
 
 public class Zsort
 {
-  public void Zsort(Vector bonds)
+  /**
+   * Sorts the Bond list in ascending order of the z-value of the bond start
+   * atom
+   * 
+   * @param bonds
+   */
+  public void sort(Vector<Bond> bonds)
   {
     sort(bonds, 0, bonds.size() - 1);
   }
 
-  public void sort(Vector bonds, int p, int r)
+  public void sort(Vector<Bond> bonds, int p, int r)
   {
     int q;
 
@@ -41,9 +47,9 @@ public class Zsort
     }
   }
 
-  private int partition(Vector bonds, int p, int r)
+  private int partition(Vector<Bond> bonds, int p, int r)
   {
-    float x = ((Bond) bonds.elementAt(p)).start[2];
+    float x = bonds.elementAt(p).start[2];
     int i = p - 1;
     int j = r + 1;
     Bond tmp;
@@ -52,17 +58,17 @@ public class Zsort
       do
       {
         j--;
-      } while ((j >= 0) && (((Bond) bonds.elementAt(j)).start[2] > x));
+      } while ((j >= 0) && (bonds.elementAt(j).start[2] > x));
 
       do
       {
         i++;
       } while ((i < bonds.size())
-              && (((Bond) bonds.elementAt(i)).start[2] < x));
+              && (bonds.elementAt(i).start[2] < x));
 
       if (i < j)
       {
-        tmp = (Bond) bonds.elementAt(i);
+        tmp = bonds.elementAt(i);
         bonds.setElementAt(bonds.elementAt(j), i);
         bonds.setElementAt(tmp, j);
       }
diff --git a/test/MCview/AtomTest.java b/test/MCview/AtomTest.java
new file mode 100644 (file)
index 0000000..8c271b3
--- /dev/null
@@ -0,0 +1,63 @@
+package MCview;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+public class AtomTest
+{
+
+  /**
+   * Test the constructor that parses a PDB file format ATOM line. Fields are in
+   * fixed column positions
+   */
+  @Test
+  public void testStringConstructor()
+  {
+    Atom a = new Atom(
+            "ATOM    349  NE2 GLN A  48      22.290   8.595  17.680  1.00 14.30           N");
+    assertEquals(349, a.atomIndex);
+    assertEquals("NE", a.name);
+    assertEquals("GLN", a.resName);
+    assertEquals("A", a.chain);
+    assertEquals(48, a.resNumber);
+    assertEquals("48", a.resNumIns);
+    assertEquals(' ', a.insCode);
+    assertEquals(22.290, a.x, 0.00001);
+    assertEquals(8.595, a.y, 0.00001);
+    assertEquals(17.680, a.z, 0.00001);
+    assertEquals(1f, a.occupancy, 0.00001);
+    assertEquals(14.3, a.tfactor, 0.00001);
+  }
+
+  /**
+   * Test the case where occupancy and temp factor are blank - should default to
+   * 1
+   */
+  @Test
+  public void testStringConstructor_blankOccupancyTempFactor()
+  {
+    Atom a = new Atom(
+            "ATOM    349  NE2 GLN A  48      22.290   8.595  17.680                       N");
+    assertEquals(1f, a.occupancy, 0.00001);
+    assertEquals(1f, a.tfactor, 0.00001);
+  }
+
+  /**
+   * Parsing non-numeric data as Atom throws an exception
+   */
+  @Test
+  public void testStringConstructor_malformed()
+  {
+    try
+    {
+      new Atom(
+              "ATOM    34N  NE2 GLN A  48      22.290   8.595  17.680  1.00 14.30           N");
+      fail("Expected exception");
+    } catch (NumberFormatException e)
+    {
+      // expected
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/MCview/BondTest.java b/test/MCview/BondTest.java
new file mode 100644 (file)
index 0000000..333bfce
--- /dev/null
@@ -0,0 +1,24 @@
+package MCview;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class BondTest
+{
+
+  @Test
+  public void testTranslate()
+  {
+    Atom a1 = new Atom(1f, 2f, 3f);
+    Atom a2 = new Atom(7f, 6f, 5f);
+    Bond b = new Bond(a1, a2);
+    b.translate(8f, 9f, 10f);
+    assertEquals(9f, b.start[0], 0.0001f);
+    assertEquals(11f, b.start[1], 0.0001f);
+    assertEquals(13f, b.start[2], 0.0001f);
+    assertEquals(15f, b.end[0], 0.0001f);
+    assertEquals(15f, b.end[1], 0.0001f);
+    assertEquals(15f, b.end[2], 0.0001f);
+  }
+}
diff --git a/test/MCview/PDBChainTest.java b/test/MCview/PDBChainTest.java
new file mode 100644 (file)
index 0000000..5be43b3
--- /dev/null
@@ -0,0 +1,393 @@
+package MCview;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.util.Vector;
+
+import org.junit.Test;
+
+import jalview.analysis.AlignSeq;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.TaylorColourScheme;
+
+public class PDBChainTest
+{
+  PDBChain c = new PDBChain("1GAQ", "A");
+  Atom a1 = new Atom(1f, 2f, 3f);
+
+  Atom a2 = new Atom(5f, 6f, 4f);
+
+  Atom a3 = new Atom(2f, 5f, 6f);
+
+  Atom a4 = new Atom(2f, 1f, 7f);
+
+  @Test
+  public void testGetNewlineString()
+  {
+    assertEquals(System.lineSeparator(), c.getNewlineString());
+    c.setNewlineString("gaga");
+    assertEquals("gaga", c.getNewlineString());
+  }
+
+  @Test
+  public void testPrint()
+  {
+    c.offset = 7;
+
+    a1.resName = "GLY";
+    a1.resNumber = 23;
+    a2.resName = "GLU";
+    a2.resNumber = 34;
+    a3.resName = "ASP";
+    a3.resNumber = 41;
+
+    Vector<Bond> v = new Vector<Bond>();
+    v.add(new Bond(a1, a2));
+    v.add(new Bond(a2, a3));
+    v.add(new Bond(a3, a1));
+    c.bonds = v;
+
+    String printed = c.print();
+    String nl = System.lineSeparator();
+    assertEquals("GLY 23 7" + nl + "GLU 34 7" + nl + "ASP 41 7" + nl,
+            printed);
+  }
+
+  /**
+   * Test the method that constructs a Bond between two atoms and adds it to the
+   * chain's list of bonds
+   */
+  @Test
+  public void testMakeBond()
+  {
+    /*
+     * Add a bond from a1 to a2
+     */
+    c.makeBond(a1, a2);
+    assertEquals(1, c.bonds.size());
+    Bond b1 = c.bonds.get(0);
+    assertSame(a1, b1.at1);
+    assertSame(a2, b1.at2);
+    assertEquals(1f, b1.start[0], 0.0001f);
+    assertEquals(2f, b1.start[1], 0.0001f);
+    assertEquals(3f, b1.start[2], 0.0001f);
+    assertEquals(5f, b1.end[0], 0.0001f);
+    assertEquals(6f, b1.end[1], 0.0001f);
+    assertEquals(4f, b1.end[2], 0.0001f);
+
+    /*
+     * Add another bond from a2 to a1
+     */
+    c.makeBond(a2, a1);
+    assertEquals(2, c.bonds.size());
+    assertSame(b1, c.bonds.get(0));
+    Bond b2 = c.bonds.get(1);
+    assertSame(a2, b2.at1);
+    assertSame(a1, b2.at2);
+    assertEquals(5f, b2.start[0], 0.0001f);
+    assertEquals(6f, b2.start[1], 0.0001f);
+    assertEquals(4f, b2.start[2], 0.0001f);
+    assertEquals(1f, b2.end[0], 0.0001f);
+    assertEquals(2f, b2.end[1], 0.0001f);
+    assertEquals(3f, b2.end[2], 0.0001f);
+  }
+
+  @Test
+  public void testSetChainColours_colour()
+  {
+    c.makeBond(a1, a2);
+    c.makeBond(a2, a3);
+    c.setChainColours(Color.PINK);
+    assertEquals(2, c.bonds.size());
+    assertEquals(Color.PINK, c.bonds.get(0).startCol);
+    assertEquals(Color.PINK, c.bonds.get(0).endCol);
+    assertEquals(Color.PINK, c.bonds.get(1).startCol);
+    assertEquals(Color.PINK, c.bonds.get(1).endCol);
+  }
+
+  /**
+   * Test setting bond start/end colours based on a colour scheme i.e. colour by
+   * residue
+   */
+  @Test
+  public void testSetChainColours_colourScheme()
+  {
+    Color alaColour = new Color(204, 255, 0);
+    Color glyColour = new Color(255, 153, 0);
+    a1.resName = "ALA";
+    a2.resName = "GLY";
+    a3.resName = "XXX"; // no colour defined
+    c.makeBond(a1, a2);
+    c.makeBond(a2, a1);
+    c.makeBond(a2, a3);
+    ColourSchemeI cs = new TaylorColourScheme();
+    c.setChainColours(cs);
+    // bond a1 to a2
+    Bond b = c.bonds.get(0);
+    assertEquals(alaColour, b.startCol);
+    assertEquals(glyColour, b.endCol);
+    // bond a2 to a1
+    b = c.bonds.get(1);
+    assertEquals(glyColour, b.startCol);
+    assertEquals(alaColour, b.endCol);
+    // bond a2 to a3 - no colour found for a3
+    // exception handling defaults to gray
+    b = c.bonds.get(2);
+    assertEquals(Color.gray, b.startCol);
+    assertEquals(Color.gray, b.endCol);
+  }
+
+  @Test
+  public void testGetChargeColour()
+  {
+    assertEquals(Color.red, PDBChain.getChargeColour("ASP"));
+    assertEquals(Color.red, PDBChain.getChargeColour("GLU"));
+    assertEquals(Color.blue, PDBChain.getChargeColour("LYS"));
+    assertEquals(Color.blue, PDBChain.getChargeColour("ARG"));
+    assertEquals(Color.yellow, PDBChain.getChargeColour("CYS"));
+    assertEquals(Color.lightGray, PDBChain.getChargeColour("ALA"));
+    assertEquals(Color.lightGray, PDBChain.getChargeColour(null));
+  }
+
+  /**
+   * Test the method that sets bond start/end colours by residue charge property
+   */
+  @Test
+  public void testSetChargeColours()
+  {
+    a1.resName = "ASP"; // red
+    a2.resName = "LYS"; // blue
+    a3.resName = "CYS"; // yellow
+    a4.resName = "ALA"; // no colour (light gray)
+    c.makeBond(a1, a2);
+    c.makeBond(a2, a3);
+    c.makeBond(a3, a4);
+    c.setChargeColours();
+    assertEquals(3, c.bonds.size());
+    // bond a1 to a2
+    Bond b = c.bonds.get(0);
+    assertEquals(Color.red, b.startCol);
+    assertEquals(Color.blue, b.endCol);
+    // bond a2 to a3
+    b = c.bonds.get(1);
+    assertEquals(Color.blue, b.startCol);
+    assertEquals(Color.yellow, b.endCol);
+    // bond a3 to a4
+    b = c.bonds.get(2);
+    assertEquals(Color.yellow, b.startCol);
+    assertEquals(Color.lightGray, b.endCol);
+  }
+
+  /**
+   * Test the method that converts the raw list of atoms to a list of residues
+   */
+  @Test
+  public void testMakeResidueList_noAnnotation()
+  {
+    Vector<Atom> atoms = new Vector<Atom>();
+    c.atoms = atoms;
+    c.isNa = true;
+    atoms.add(makeAtom(4, "N", "MET"));
+    atoms.add(makeAtom(4, "CA", "MET"));
+    atoms.add(makeAtom(4, "C", "MET"));
+    atoms.add(makeAtom(5, "O", "LYS"));
+    atoms.add(makeAtom(5, "N", "LYS"));
+    atoms.add(makeAtom(5, "CA", "LYS"));
+    atoms.add(makeAtom(6, "O", "LEU"));
+    atoms.add(makeAtom(6, "N", "LEU"));
+    atoms.add(makeAtom(6, "CA", "LEU"));
+
+    c.makeResidueList(false);
+
+    /*
+     * check sequence constructed
+     */
+    assertEquals("MKL", c.sequence.getSequenceAsString());
+    assertFalse(c.isNa);
+    assertEquals(3, c.residues.size());
+
+    /*
+     * check sequence features
+     */
+    SequenceFeature[] sfs = c.sequence.getSequenceFeatures();
+    assertEquals(3, sfs.length);
+    assertEquals("RESNUM", sfs[0].type);
+    assertEquals("MET:4 1gaqA", sfs[0].description);
+    assertEquals(4, sfs[0].begin);
+    assertEquals(4, sfs[0].end);
+    assertEquals("RESNUM", sfs[0].type);
+    assertEquals("LYS:5 1gaqA", sfs[1].description);
+    assertEquals(5, sfs[1].begin);
+    assertEquals(5, sfs[1].end);
+    assertEquals("LEU:6 1gaqA", sfs[2].description);
+    assertEquals(6, sfs[2].begin);
+    assertEquals(6, sfs[2].end);
+  }
+
+  private Atom makeAtom(int resnum, String name, String resname)
+  {
+    Atom a = new Atom(1f, 2f, 3f);
+    a.resNumber = resnum;
+    a.resNumIns = String.valueOf(resnum);
+    a.name = name;
+    a.resName = resname;
+    a.chain = "A";
+    return a;
+  }
+
+  /**
+   * Test the method that converts the raw list of atoms to a list of residues,
+   * including parsing of tempFactor to an alignment annotation
+   */
+  @Test
+  public void testMakeResidueList_withTempFactor()
+  {
+    Vector<Atom> atoms = new Vector<Atom>();
+    c.atoms = atoms;
+    atoms.add(makeAtom(4, "N", "MET"));
+    atoms.get(atoms.size()-1).tfactor = 1f;
+    atoms.add(makeAtom(4, "CA", "MET"));
+    atoms.get(atoms.size()-1).tfactor = 2f;
+    atoms.add(makeAtom(4, "C", "MET"));
+    atoms.get(atoms.size()-1).tfactor = 3f;
+    atoms.add(makeAtom(5, "O", "LYS"));
+    atoms.get(atoms.size()-1).tfactor = 7f;
+    atoms.add(makeAtom(5, "N", "LYS"));
+    atoms.get(atoms.size()-1).tfactor = 8f;
+    atoms.add(makeAtom(5, "CA", "LYS"));
+    atoms.get(atoms.size()-1).tfactor = 9f;
+    atoms.add(makeAtom(6, "O", "LEU"));
+    atoms.get(atoms.size()-1).tfactor = 4f;
+    atoms.add(makeAtom(6, "N", "LEU"));
+    atoms.get(atoms.size()-1).tfactor = 5f;
+    atoms.add(makeAtom(6, "CA", "LEU"));
+    atoms.get(atoms.size()-1).tfactor = 6f;
+  
+    /*
+     * make residues including temp factor annotation
+     */
+    c.makeResidueList(true);
+    
+    /*
+     * Verify annotations; note the tempFactor is read from the first atom in
+     * each residue i.e. we expect values 1, 7, 4 for the residues
+     */
+    AlignmentAnnotation[] ann = c.sequence.getAnnotation();
+    assertEquals(1, ann.length);
+    assertEquals("Temperature Factor", ann[0].label);
+    assertEquals("Temperature Factor for 1gaqA", ann[0].description);
+    assertSame(c.sequence, ann[0].sequenceRef);
+    assertEquals(AlignmentAnnotation.LINE_GRAPH, ann[0].graph);
+    assertEquals(0f, ann[0].graphMin, 0.001f);
+    assertEquals(7f, ann[0].graphMax, 0.001f);
+    assertEquals(3, ann[0].annotations.length);
+    assertEquals(1f, ann[0].annotations[0].value, 0.001f);
+    assertEquals(7f, ann[0].annotations[1].value, 0.001f);
+    assertEquals(4f, ann[0].annotations[2].value, 0.001f);
+  }
+
+  /**
+   * Test the method that constructs bonds between successive residues' CA or P
+   * atoms
+   */
+  @Test
+  public void testMakeCaBondList()
+  {
+    c.isNa = true;
+    Vector<Atom> atoms = new Vector<Atom>();
+    c.atoms = atoms;
+    atoms.add(makeAtom(4, "N", "MET"));
+    atoms.add(makeAtom(4, "CA", "MET"));
+    atoms.add(makeAtom(5, "CA", "ASP"));
+    atoms.add(makeAtom(5, "O", "ASP"));
+    atoms.add(makeAtom(6, "CA", "GLY"));
+    atoms.add(makeAtom(6, "N", "GLY"));
+
+    // have to make residue list first!
+    c.makeResidueList(false);
+    assertFalse(c.isNa);
+    c.isNa = true;
+
+    c.makeCaBondList();
+    assertEquals(2, c.bonds.size());
+    Bond b = c.bonds.get(0);
+    assertSame(c.atoms.get(1), b.at1);
+    assertSame(c.atoms.get(2), b.at2);
+    b = c.bonds.get(1);
+    assertSame(c.atoms.get(2), b.at1);
+    assertSame(c.atoms.get(4), b.at2);
+
+    // isNa flag is _not_ reset by this method!
+    assertTrue(c.isNa);
+  }
+
+  @Test
+  public void testMakeCaBondList_nucleotide()
+  {
+    c.isNa = false;
+    Vector<Atom> atoms = new Vector<Atom>();
+    c.atoms = atoms;
+    atoms.add(makeAtom(4, "N", "G"));
+    atoms.add(makeAtom(4, "P", "G"));
+    atoms.add(makeAtom(5, "P", "C"));
+    atoms.add(makeAtom(5, "O", "C"));
+    atoms.add(makeAtom(6, "P", "T"));
+    atoms.add(makeAtom(6, "N", "T"));
+
+    // have to make residue list first!
+    c.makeResidueList(false);
+    assertEquals("GCT", c.sequence.getSequenceAsString());
+
+    c.makeCaBondList();
+    assertEquals(2, c.bonds.size());
+    Bond b = c.bonds.get(0);
+    assertSame(c.atoms.get(1), b.at1);
+    assertSame(c.atoms.get(2), b.at2);
+    b = c.bonds.get(1);
+    assertSame(c.atoms.get(2), b.at1);
+    assertSame(c.atoms.get(4), b.at2);
+
+    assertTrue(c.isNa);
+  }
+
+  /**
+   * Test the method that updates atoms with their alignment positions
+   */
+  @Test
+  public void testMakeExactMapping()
+  {
+    Vector<Atom> atoms = new Vector<Atom>();
+    c.atoms = atoms;
+    atoms.add(makeAtom(4, "N", "MET"));
+    atoms.add(makeAtom(4, "CA", "MET"));
+    atoms.add(makeAtom(5, "CA", "ASP"));
+    atoms.add(makeAtom(5, "O", "ASP"));
+    atoms.add(makeAtom(6, "CA", "GLY"));
+    atoms.add(makeAtom(6, "N", "GLY"));
+    c.makeResidueList(false);
+    assertEquals("MDG", c.sequence.getSequenceAsString());
+    SequenceI s1 = new Sequence("Seq1", "MDG");
+    SequenceI s2 = new Sequence("Seq2", "MDG");
+    AlignSeq alignSeq = AlignSeq.doGlobalNWAlignment(s1, s2, AlignSeq.PEP);
+    SequenceI seq3 = new Sequence("Seq3", "--M-DG");
+    c.makeExactMapping(alignSeq, seq3);
+
+    int pos = 0;
+    for (Residue res : c.residues)
+    {
+      for (Atom a : res.atoms)
+      {
+        assertEquals(pos, a.alignmentMapping);
+      }
+      pos++;
+    }
+  }
+}
diff --git a/test/MCview/PDBfileTest.java b/test/MCview/PDBfileTest.java
new file mode 100644 (file)
index 0000000..9ebed25
--- /dev/null
@@ -0,0 +1,272 @@
+package MCview;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+
+public class PDBfileTest
+{
+  @Test
+  public void testIsRna()
+  {
+    SequenceI seq = new Sequence("Seq1", "CGAU");
+    assertTrue(PDBfile.isRNA(seq));
+
+    seq.setSequence("CGAu");
+    assertFalse(PDBfile.isRNA(seq));
+
+    seq.setSequence("CGAT");
+    assertFalse(PDBfile.isRNA(seq));
+
+    seq.setSequence("GRSWYFLAVM");
+    assertFalse(PDBfile.isRNA(seq));
+  }
+
+  /**
+   * Test the 'high level' outputs of parsing. More detailed tests in
+   * PDBChainTest.
+   * 
+   * @throws IOException
+   */
+  @Test
+  public void testParse() throws IOException
+  {
+    /*
+     * Constructor with file path performs parse()
+     */
+    PDBfile pf = new PDBfile(false, false, false, "examples/3W5V.pdb",
+            AppletFormatAdapter.FILE);
+
+    assertEquals("3W5V", pf.id);
+    // verify no alignment annotations created
+    assertNull(getAlignmentAnnotations(pf));
+
+    assertEquals(4, pf.chains.size());
+    assertEquals("A", pf.chains.get(0).id);
+    assertEquals("B", pf.chains.get(1).id);
+    assertEquals("C", pf.chains.get(2).id);
+    assertEquals("D", pf.chains.get(3).id);
+
+    PDBChain chainA = pf.chains.get(0);
+    assertEquals(0, chainA.seqstart); // not set
+    assertEquals(0, chainA.seqend); // not set
+    assertEquals(18, chainA.sequence.getStart());
+    assertEquals(314, chainA.sequence.getEnd());
+    assertTrue(chainA.sequence.getSequenceAsString().startsWith("KCSKKQEE"));
+    assertTrue(chainA.sequence.getSequenceAsString().endsWith("WNVEVY"));
+    assertEquals("3W5V|A", chainA.sequence.getName());
+    assertNull(chainA.sequence.getAnnotation());
+    assertEquals(1, chainA.sequence.getPDBId().size());
+    PDBEntry pdb = chainA.sequence.getPDBId().get(0);
+    assertEquals("A", pdb.getChainCode());
+    assertEquals("PDB", pdb.getType());
+    assertEquals("3W5V", pdb.getId());
+
+    PDBChain chainB = pf.chains.get(1);
+    assertEquals(1, chainB.sequence.getStart());
+    assertEquals(96, chainB.sequence.getEnd());
+    assertTrue(chainB.sequence.getSequenceAsString().startsWith("ATYNVK"));
+    assertTrue(chainB.sequence.getSequenceAsString().endsWith("KEEELT"));
+    assertEquals("3W5V|B", chainB.sequence.getName());
+
+    PDBChain chainC = pf.chains.get(2);
+    assertEquals(18, chainC.sequence.getStart());
+    assertEquals(314, chainC.sequence.getEnd());
+    assertTrue(chainC.sequence.getSequenceAsString().startsWith("KCSKKQEE"));
+    assertTrue(chainC.sequence.getSequenceAsString().endsWith("WNVEVY"));
+    assertEquals("3W5V|C", chainC.sequence.getName());
+
+    PDBChain chainD = pf.chains.get(3);
+    assertEquals(1, chainD.sequence.getStart());
+    assertEquals(96, chainD.sequence.getEnd());
+    assertTrue(chainD.sequence.getSequenceAsString().startsWith("ATYNVK"));
+    assertTrue(chainD.sequence.getSequenceAsString().endsWith("KEEELT"));
+    assertEquals("3W5V|D", chainD.sequence.getName());
+  }
+
+  /**
+   * Test parsing, with annotations added to the alignment but no secondary
+   * structure prediction
+   * 
+   * @throws IOException
+   */
+  @Test
+  public void testParse_withAnnotations_noSS() throws IOException
+  {
+    PDBfile pf = new PDBfile(true, false, false, "examples/3W5V.pdb",
+            AppletFormatAdapter.FILE);
+
+    AlignmentAnnotation[] anns = getAlignmentAnnotations(pf);
+    assertEquals(4, anns.length);
+
+    /*
+     * Inspect temp factor annotation for chain A
+     */
+    AlignmentAnnotation chainAnnotation = anns[0];
+    assertEquals("Temperature Factor", chainAnnotation.label);
+    // PDBChain constructor changes PDB id to lower case (why?)
+    assertEquals("Temperature Factor for 3w5vA",
+            chainAnnotation.description);
+    assertSame(pf.getSeqs().get(0), chainAnnotation.sequenceRef);
+    assertEquals(AlignmentAnnotation.LINE_GRAPH, chainAnnotation.graph);
+    assertEquals(0f, chainAnnotation.graphMin, 0.001f);
+    assertEquals(40f, chainAnnotation.graphMax, 0.001f);
+    assertEquals(297, chainAnnotation.annotations.length);
+    assertEquals(40f, chainAnnotation.annotations[0].value, 0.001f);
+
+    /*
+     * Chain B temp factor
+     */
+    chainAnnotation = anns[1];
+    assertEquals("Temperature Factor for 3w5vB",
+            chainAnnotation.description);
+    assertSame(pf.getSeqs().get(1), chainAnnotation.sequenceRef);
+    assertEquals(96, chainAnnotation.annotations.length);
+
+    /*
+     * Chain C temp factor
+     */
+    chainAnnotation = anns[2];
+    assertEquals("Temperature Factor for 3w5vC",
+            chainAnnotation.description);
+    assertSame(pf.getSeqs().get(2), chainAnnotation.sequenceRef);
+    assertEquals(297, chainAnnotation.annotations.length);
+
+    /*
+     * Chain D temp factor
+     */
+    chainAnnotation = anns[3];
+    assertEquals("Temperature Factor for 3w5vD",
+            chainAnnotation.description);
+    assertSame(pf.getSeqs().get(3), chainAnnotation.sequenceRef);
+    assertEquals(96, chainAnnotation.annotations.length);
+  }
+
+  /**
+   * Test parsing including secondary structure annotation using JMol; this test
+   * for the case where flag to add annotations to alignment is set false
+   * 
+   * @throws IOException
+   */
+  @Test
+  public void testParse_withJmol_noAnnotations() throws IOException
+  {
+    PDBfile pf = new PDBfile(false, true, false, "examples/3W5V.pdb",
+            AppletFormatAdapter.FILE);
+
+    /*
+     * alignment annotations _are_ created anyway (in
+     * AlignSeq.replaceMatchingSeqsWith())
+     */
+    final AlignmentAnnotation[] anns = getAlignmentAnnotations(pf);
+    assertEquals(4, anns.length);
+
+    /*
+     * no sequence annotations created - tempFactor annotation is not added
+     * unless the flag to 'addAlignmentAnnotations' is set true
+     */
+    for (PDBChain c : pf.chains)
+    {
+      assertNull(c.sequence.getAnnotation());
+    }
+  }
+
+  /**
+   * Test parsing including secondary structure prediction and annotation using
+   * JMol
+   * 
+   * @throws IOException
+   */
+  @Test
+  public void testParse_withJmolAddAlignmentAnnotations()
+          throws IOException
+  {
+    PDBfile pf = new PDBfile(true, true, false, "examples/3W5V.pdb",
+            AppletFormatAdapter.FILE);
+
+    /*
+     * Alignment annotations for TempFactor, SecStruct, per sequence (chain)
+     */
+    AlignmentAnnotation[] anns = getAlignmentAnnotations(pf);
+    assertEquals(8, anns.length);
+
+    /*
+     * other tests have detailed assertions for Temp Factor annotations
+     */
+    assertEquals("Temperature Factor for 3w5vA", anns[1].description);
+    assertEquals("Temperature Factor for 3w5vB", anns[3].description);
+    assertEquals("Temperature Factor for 3w5vC", anns[5].description);
+    assertEquals("Temperature Factor for 3w5vD", anns[7].description);
+
+    /*
+     * PDBFileWithJmol (unlike PDBChain!) leaves PDB id upper case
+     */
+    assertEquals("Secondary Structure for 3W5VA", anns[0].description);
+    assertEquals("Secondary Structure for 3W5VB", anns[2].description);
+    assertEquals("Secondary Structure for 3W5VC", anns[4].description);
+    assertEquals("Secondary Structure for 3W5VD", anns[6].description);
+
+    /*
+     * Verify SS annotations are linked to respective sequences (chains)
+     */
+    assertSame(pf.getSeqs().get(0), anns[0].sequenceRef);
+    assertSame(pf.getSeqs().get(1), anns[2].sequenceRef);
+    assertSame(pf.getSeqs().get(2), anns[4].sequenceRef);
+    assertSame(pf.getSeqs().get(3), anns[6].sequenceRef);
+
+    /*
+     * Verify a sample of SS predictions
+     */
+    for (int i = 0; i < 20; i++)
+    {
+      assertNull(anns[0].annotations[i]);
+      assertEquals("E", anns[0].annotations[20].displayCharacter);
+      assertEquals('E', anns[0].annotations[20].secondaryStructure);
+      assertEquals("E", anns[2].annotations[18].displayCharacter);
+      assertEquals("H", anns[2].annotations[23].displayCharacter);
+    }
+  }
+
+  /**
+   * Placeholder for a test of parsing RNA structure with secondary structure
+   * prediction using the Annotate3D service
+   * 
+   * @throws IOException
+   */
+  @Test
+  @Ignore
+  public void testParse_withAnnotate3D() throws IOException
+  {
+    // TODO requires a mock for Annotate3D processing
+    // and/or run as an integration test
+    PDBfile pf = new PDBfile(true, true, true, "examples/2GIS.pdb",
+            AppletFormatAdapter.FILE);
+  }
+  /**
+   * Helper method to extract parsed annotations from the PDBfile
+   * 
+   * @param pf
+   * @return
+   */
+  private AlignmentAnnotation[] getAlignmentAnnotations(PDBfile pf)
+  {
+    AlignmentI al = new Alignment(pf.getSeqsAsArray());
+    pf.addAnnotations(al);
+    return al.getAlignmentAnnotation();
+  }
+  }
diff --git a/test/MCview/ResidueTest.java b/test/MCview/ResidueTest.java
new file mode 100644 (file)
index 0000000..ed98c5b
--- /dev/null
@@ -0,0 +1,36 @@
+package MCview;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Vector;
+
+import org.junit.Test;
+
+public class ResidueTest
+{
+
+  @Test
+  public void testFindAtom()
+  {
+    Atom a1 = new Atom(1f, 2f, 3f);
+    a1.name = "C";
+    Atom a2 = new Atom(1f, 2f, 3f);
+    a2.name = "A";
+    Atom a3 = new Atom(1f, 2f, 3f);
+    a3.name = "P";
+    Atom a4 = new Atom(1f, 2f, 3f);
+    a4.name = "C";
+    Vector<Atom> v = new Vector<Atom>();
+    v.add(a1);
+    v.add(a2);
+    v.add(a3);
+    v.add(a4);
+    Residue r = new Residue(v, 293, 12);
+
+    assertSame(a1, r.findAtom("C"));
+    assertSame(a2, r.findAtom("A"));
+    assertSame(a3, r.findAtom("P"));
+    assertNull(r.findAtom("S"));
+  }
+}