JAL-2196 refactor PDBEntry.getProperty,setProperty,getProperties
[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.getConstructor(new Class[] {
286             boolean.class, boolean.class, boolean.class, FileParse.class });
287         final Object[] args = new Object[] { visibleChainAnnotation,
288             predictSecondaryStructure, externalSecondaryStructure,
289             new FileParse(getDataName(), type) };
290
291         StructureImportSettings.setShowSeqFeatures(false);
292         StructureImportSettings.setVisibleChainAnnotation(false);
293         StructureImportSettings
294                 .setProcessSecondaryStructure(predictSecondaryStructure);
295         StructureImportSettings
296                 .setExternalSecondaryStructure(externalSecondaryStructure);
297         Object jmf = constructor.newInstance(args);
298         AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
299                 "getSeqsAsArray", new Class[] {}).invoke(jmf));
300         cl.getMethod("addAnnotations", new Class[] { AlignmentI.class })
301                 .invoke(jmf, al);
302         for (SequenceI sq : al.getSequences())
303         {
304           if (sq.getDatasetSequence() != null)
305           {
306             sq.getDatasetSequence().getAllPDBEntries().clear();
307           }
308           else
309           {
310             sq.getAllPDBEntries().clear();
311           }
312         }
313         replaceAndUpdateChains(prot, al, AlignSeq.PEP, false);
314       }
315     } catch (ClassNotFoundException q)
316     {
317     }
318     StructureImportSettings.setShowSeqFeatures(true);
319   }
320
321   public PDBChain findChain(String id) throws Exception
322   {
323     for (PDBChain chain : getChains())
324     {
325       if (chain.id.equals(id))
326       {
327         return chain;
328       }
329     }
330     throw new Exception("PDB chain not Found!");
331   }
332
333   public void makeResidueList()
334   {
335     for (PDBChain chain : getChains())
336     {
337       chain.makeResidueList(visibleChainAnnotation);
338     }
339   }
340
341   public void makeCaBondList()
342   {
343     for (PDBChain chain : getChains())
344     {
345       chain.makeCaBondList();
346     }
347   }
348
349   public void setChargeColours()
350   {
351     for (PDBChain chain : getChains())
352     {
353       chain.setChargeColours();
354     }
355   }
356
357   public void setColours(jalview.schemes.ColourSchemeI cs)
358   {
359     for (PDBChain chain : getChains())
360     {
361       chain.setChainColours(cs);
362     }
363   }
364
365   public void setChainColours()
366   {
367     int i = 0;
368     for (PDBChain chain : getChains())
369     {
370       chain.setChainColours(Color.getHSBColor(1.0f / i++, .4f, 1.0f));
371     }
372   }
373
374   public static boolean isRNA(SequenceI seq)
375   {
376     for (char c : seq.getSequence())
377     {
378       if ((c != 'A') && (c != 'C') && (c != 'G') && (c != 'U'))
379       {
380         return false;
381       }
382     }
383     return true;
384   }
385
386   /**
387    * make a friendly ID string.
388    * 
389    * @param dataName
390    * @return truncated dataName to after last '/'
391    */
392   protected String safeName(String dataName)
393   {
394     int p = 0;
395     while ((p = dataName.indexOf("/")) > -1 && p < dataName.length())
396     {
397       dataName = dataName.substring(p + 1);
398     }
399     return dataName;
400   }
401
402   public String getId()
403   {
404     return id;
405   }
406
407   public void setId(String id)
408   {
409     this.id = id;
410   }
411
412   public Vector<PDBChain> getChains()
413   {
414     return chains;
415   }
416
417   public void setChains(Vector<PDBChain> chains)
418   {
419     this.chains = chains;
420   }
421
422   public Type getDbRefType()
423   {
424     return dbRefType;
425   }
426
427   public void setDbRefType(String dbRefType)
428   {
429     this.dbRefType = Type.getType(dbRefType);
430   }
431
432   public void setDbRefType(Type dbRefType)
433   {
434     this.dbRefType = dbRefType;
435   }
436
437   /**
438    * Returns a descriptor for suitable feature display settings with
439    * <ul>
440    * <li>ResNums or insertions features visible</li>
441    * <li>insertions features coloured red</li>
442    * <li>ResNum features coloured by label</li>
443    * <li>Insertions displayed above (on top of) ResNums</li>
444    * </ul>
445    */
446   @Override
447   public FeatureSettingsModelI getFeatureColourScheme()
448   {
449     return new PDBFeatureSettings();
450   }
451 }