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