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