JAL-1919 refined structure view annotation settings to work for both PDB and mmCIF
[jalview.git] / src / jalview / io / StructureFile.java
1 package jalview.io;
2
3 import jalview.analysis.AlignSeq;
4 import jalview.datamodel.Alignment;
5 import jalview.datamodel.AlignmentAnnotation;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.DBRefEntry;
8 import jalview.datamodel.DBRefSource;
9 import jalview.datamodel.PDBEntry;
10 import jalview.datamodel.SequenceI;
11 import jalview.structure.StructureViewSettings;
12
13 import java.awt.Color;
14 import java.io.IOException;
15 import java.lang.reflect.Constructor;
16 import java.util.Hashtable;
17 import java.util.List;
18 import java.util.Vector;
19
20 import MCview.PDBChain;
21
22 public abstract class StructureFile extends AlignFile
23 {
24
25   private String id;
26
27   private String dbRefType;
28   /**
29    * set to true to add derived sequence annotations (temp factor read from
30    * file, or computed secondary structure) to the alignment
31    */
32   protected boolean visibleChainAnnotation = false;
33
34   /**
35    * Set true to predict secondary structure (using JMol for protein, Annotate3D
36    * for RNA)
37    */
38   protected boolean predictSecondaryStructure = false;
39
40   /**
41    * Set true (with predictSecondaryStructure=true) to predict secondary
42    * structure using an external service (currently Annotate3D for RNA only)
43    */
44   protected boolean externalSecondaryStructure = false;
45
46   private Vector<PDBChain> chains;
47
48   public StructureFile(String inFile, String type) throws IOException
49   {
50     super(inFile, type);
51   }
52
53   public StructureFile(FileParse fp) throws IOException
54   {
55     super(fp);
56   }
57
58   public void addSettings(boolean addAlignmentAnnotations,
59           boolean predictSecondaryStructure, boolean externalSecStr)
60   {
61     this.visibleChainAnnotation = addAlignmentAnnotations;
62     this.predictSecondaryStructure = predictSecondaryStructure;
63     this.externalSecondaryStructure = externalSecStr;
64   }
65   public StructureFile(boolean parseImmediately, String inFile, String type)
66           throws IOException
67   {
68     super(parseImmediately, inFile, type);
69   }
70
71   public StructureFile(boolean a, FileParse fp) throws IOException
72   {
73     super(a, fp);
74   }
75
76   public StructureFile()
77   {
78   }
79
80   @SuppressWarnings("rawtypes")
81   protected SequenceI postProcessChain(PDBChain chain)
82   {
83     SequenceI pdbSequence = chain.sequence;
84     pdbSequence.setName(getId() + "|" + pdbSequence.getName());
85     PDBEntry entry = new PDBEntry();
86     entry.setId(getId());
87     entry.setType(this.dbRefType);
88     entry.setProperty(new Hashtable());
89     if (chain.id != null)
90     {
91       entry.setChainCode(String.valueOf(chain.id));
92     }
93     if (inFile != null)
94     {
95       entry.setFile(inFile.getAbsolutePath());
96     }
97     else
98     {
99       entry.setFile(getDataName());
100     }
101
102     DBRefEntry sourceDBRef = new DBRefEntry();
103     sourceDBRef.setAccessionId(getId());
104     sourceDBRef.setSource(DBRefSource.PDB);
105     sourceDBRef.setStartRes(pdbSequence.getStart());
106     sourceDBRef.setEndRes(pdbSequence.getEnd());
107
108     SequenceI chainseq = pdbSequence.deriveSequence();
109     chainseq.setSourceDBRef(sourceDBRef);
110     chainseq.addPDBId(entry);
111     chainseq.addDBRef(sourceDBRef);
112
113     seqs.addElement(chainseq);
114
115     AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
116
117     if (chainannot != null && visibleChainAnnotation)
118     {
119       for (int ai = 0; ai < chainannot.length; ai++)
120       {
121         chainannot[ai].visible = visibleChainAnnotation;
122         annotations.addElement(chainannot[ai]);
123       }
124     }
125     return chainseq;
126   }
127
128   @SuppressWarnings({ "unchecked", "rawtypes" })
129   protected void processPdbFileWithAnnotate3d(List<SequenceI> rna)
130           throws Exception
131   {
132     // System.out.println("this is a PDB format and RNA sequence");
133     // note: we use reflection here so that the applet can compile and run
134     // without the HTTPClient bits and pieces needed for accessing Annotate3D
135     // web service
136     try
137     {
138       Class cl = Class.forName("jalview.ws.jws1.Annotate3D");
139       if (cl != null)
140       {
141         // TODO: use the PDB ID of the structure if one is available, to save
142         // bandwidth and avoid uploading the whole structure to the service
143         Object annotate3d = cl.getConstructor(new Class[] {}).newInstance(
144                 new Object[] {});
145         AlignmentI al = ((AlignmentI) cl.getMethod("getRNAMLFor",
146                 new Class[] { FileParse.class }).invoke(annotate3d,
147                 new Object[] { new FileParse(getDataName(), type) }));
148         for (SequenceI sq : al.getSequences())
149         {
150           if (sq.getDatasetSequence() != null)
151           {
152             if (sq.getDatasetSequence().getAllPDBEntries() != null)
153             {
154               sq.getDatasetSequence().getAllPDBEntries().clear();
155             }
156           }
157           else
158           {
159             if (sq.getAllPDBEntries() != null)
160             {
161               sq.getAllPDBEntries().clear();
162             }
163           }
164         }
165         replaceAndUpdateChains(rna, al, AlignSeq.DNA, false);
166       }
167     } catch (ClassNotFoundException x)
168     {
169       // ignore classnotfounds - occurs in applet
170     }
171   }
172
173   @SuppressWarnings("unchecked")
174   protected void replaceAndUpdateChains(List<SequenceI> prot,
175           AlignmentI al,
176           String pep, boolean b)
177   {
178     List<List<? extends Object>> replaced = AlignSeq
179             .replaceMatchingSeqsWith(seqs, annotations, prot, al, pep,
180                     false);
181     for (PDBChain ch : getChains())
182     {
183       int p = 0;
184       for (SequenceI sq : (List<SequenceI>) replaced.get(0))
185       {
186         p++;
187         if (sq == ch.sequence || sq.getDatasetSequence() == ch.sequence)
188         {
189           p = -p;
190           break;
191         }
192       }
193       if (p < 0)
194       {
195         p = -p - 1;
196         // set shadow entry for chains
197         ch.shadow = (SequenceI) replaced.get(1).get(p);
198         ch.shadowMap = ((AlignSeq) replaced.get(2).get(p))
199                 .getMappingFromS1(false);
200       }
201     }
202   }
203
204   /**
205    * Predict secondary structure for RNA and/or protein sequences and add as
206    * annotations
207    * 
208    * @param rnaSequences
209    * @param proteinSequences
210    */
211   protected void addSecondaryStructure(List<SequenceI> rnaSequences,
212           List<SequenceI> proteinSequences)
213   {
214     /*
215      * Currently using Annotate3D for RNA, but only if the 'use external
216      * prediction' flag is set
217      */
218     if (externalSecondaryStructure && rnaSequences.size() > 0)
219     {
220       try
221       {
222         processPdbFileWithAnnotate3d(rnaSequences);
223       } catch (Exception x)
224       {
225         System.err.println("Exceptions when dealing with RNA in pdb file");
226         x.printStackTrace();
227
228       }
229     }
230
231     /*
232      * Currently using JMol PDB parser for peptide
233      */
234     if (proteinSequences.size() > 0)
235     {
236       try
237       {
238         processWithJmolParser(proteinSequences);
239       } catch (Exception x)
240       {
241         System.err
242                 .println("Exceptions from Jmol when processing data in pdb file");
243         x.printStackTrace();
244       }
245     }
246   }
247
248   @SuppressWarnings({ "unchecked", "rawtypes" })
249   private void processWithJmolParser(List<SequenceI> prot)
250           throws Exception
251   {
252     try
253     {
254
255       Class cl = Class.forName("jalview.ext.jmol.JmolParser");
256       if (cl != null)
257       {
258         final Constructor constructor = cl
259 .getConstructor(new Class[] {
260             boolean.class, boolean.class, boolean.class, FileParse.class });
261         final Object[] args = new Object[] { true, true, true,
262             new FileParse(getDataName(),
263                 type) };
264
265         StructureViewSettings.setShowSeqFeatures(false);
266         StructureViewSettings.setPredictSecondaryStructure(true);
267         Object jmf = constructor.newInstance(args);
268         AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
269                 "getSeqsAsArray", new Class[] {}).invoke(jmf));
270         cl.getMethod("addAnnotations", new Class[] { AlignmentI.class })
271                 .invoke(jmf, al);
272         for (SequenceI sq : al.getSequences())
273         {
274           if (sq.getDatasetSequence() != null)
275           {
276             sq.getDatasetSequence().getAllPDBEntries().clear();
277           }
278           else
279           {
280             sq.getAllPDBEntries().clear();
281           }
282         }
283         replaceAndUpdateChains(prot, al, AlignSeq.PEP, false);
284       }
285     } catch (ClassNotFoundException q)
286     {
287     }
288   }
289
290   public PDBChain findChain(String id) throws Exception
291   {
292     for (PDBChain chain : getChains())
293     {
294       if (chain.id.equalsIgnoreCase(id))
295       {
296         return chain;
297       }
298     }
299     throw new Exception("PDB chain not Found!");
300   }
301
302   public void makeResidueList()
303   {
304     for (PDBChain chain : getChains())
305     {
306       chain.makeResidueList(visibleChainAnnotation);
307     }
308   }
309
310   public void makeCaBondList()
311   {
312     for (PDBChain chain : getChains())
313     {
314       chain.makeCaBondList();
315     }
316   }
317
318   public void setChargeColours()
319   {
320     for (PDBChain chain : getChains())
321     {
322       chain.setChargeColours();
323     }
324   }
325
326   public void setColours(jalview.schemes.ColourSchemeI cs)
327   {
328     for (PDBChain chain : getChains())
329     {
330       chain.setChainColours(cs);
331     }
332   }
333
334   public void setChainColours()
335   {
336     int i = 0;
337     for (PDBChain chain : getChains())
338     {
339       chain.setChainColours(Color.getHSBColor(1.0f / i++, .4f, 1.0f));
340     }
341   }
342
343   public static boolean isRNA(SequenceI seq)
344   {
345     for (char c : seq.getSequence())
346     {
347       if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'U'))
348       {
349         return false;
350       }
351     }
352     return true;
353   }
354
355   /**
356    * make a friendly ID string.
357    * 
358    * @param dataName
359    * @return truncated dataName to after last '/'
360    */
361   protected String safeName(String dataName)
362   {
363     int p = 0;
364     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
365     {
366       dataName = dataName.substring(p + 1);
367     }
368     return dataName;
369   }
370
371   public String getId()
372   {
373     return id;
374   }
375
376   public void setId(String id)
377   {
378     this.id = id;
379   }
380
381   public Vector<PDBChain> getChains()
382   {
383     return chains;
384   }
385
386   public void setChains(Vector<PDBChain> chains)
387   {
388     this.chains = chains;
389   }
390
391   public String getDbRefType()
392   {
393     return dbRefType;
394   }
395
396   public void setDbRefType(String dbRefType)
397   {
398     this.dbRefType = dbRefType;
399   }
400 }