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