989227bbca69577a400bb543d699baaf86929e89
[jalview.git] / src / jalview / gui / SequenceFetcher.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.gui;\r
20 \r
21 import java.io.*;\r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 import javax.swing.*;\r
27 \r
28 import MCview.*;\r
29 import jalview.datamodel.*;\r
30 import jalview.datamodel.xdb.embl.*;\r
31 import java.io.File;\r
32 import jalview.io.*;\r
33 import java.awt.Rectangle;\r
34 import java.awt.BorderLayout;\r
35 import java.awt.Dimension;\r
36 \r
37 public class SequenceFetcher\r
38 extends JPanel implements Runnable\r
39 {\r
40   JInternalFrame frame;\r
41   AlignFrame alignFrame;\r
42   StringBuffer result;\r
43   final String noDbSelected = "-- Select Database --";\r
44   public SequenceFetcher(AlignFrame af)\r
45   {\r
46     alignFrame = af;\r
47     database.addItem(noDbSelected);\r
48     database.addItem("Uniprot");\r
49     database.addItem("EMBL");\r
50     database.addItem("EMBLCDS");\r
51     database.addItem("PDB");\r
52     database.addItem("PFAM");\r
53 \r
54     try\r
55     {\r
56       jbInit();\r
57     }\r
58     catch (Exception ex)\r
59     {\r
60       ex.printStackTrace();\r
61     }\r
62 \r
63     frame = new JInternalFrame();\r
64     frame.setContentPane(this);\r
65     if (System.getProperty("os.name").startsWith("Mac"))\r
66     {\r
67       Desktop.addInternalFrame(frame, getFrameTitle(), 400, 140);\r
68     }\r
69     else\r
70     {\r
71       Desktop.addInternalFrame(frame, getFrameTitle(), 400, 125);\r
72     }\r
73   }\r
74 \r
75   private String getFrameTitle()\r
76   {\r
77     return ( (alignFrame == null) ? "New " : "Additional ") +\r
78     "Sequence Fetcher";\r
79   }\r
80 \r
81   private void jbInit()\r
82   throws Exception\r
83   {\r
84     this.setLayout(borderLayout2);\r
85 \r
86     database.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
87     jLabel1.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));\r
88     jLabel1.setHorizontalAlignment(SwingConstants.CENTER);\r
89     jLabel1.setText(\r
90     "Separate multiple accession ids with semi colon \";\"");\r
91     ok.setText("OK");\r
92     ok.addActionListener(new ActionListener()\r
93     {\r
94       public void actionPerformed(ActionEvent e)\r
95       {\r
96         ok_actionPerformed();\r
97       }\r
98     });\r
99     close.setText("Close");\r
100     close.addActionListener(new ActionListener()\r
101     {\r
102       public void actionPerformed(ActionEvent e)\r
103       {\r
104         close_actionPerformed(e);\r
105       }\r
106     });\r
107     textArea.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
108     textArea.setLineWrap(true);\r
109     textArea.addKeyListener(new KeyAdapter()\r
110     {\r
111       public void keyPressed(KeyEvent e)\r
112       {\r
113         if(e.getKeyCode()==KeyEvent.VK_ENTER)\r
114           ok_actionPerformed();\r
115       }\r
116     });\r
117     jPanel3.setLayout(borderLayout1);\r
118     borderLayout1.setVgap(5);\r
119     jPanel1.add(ok);\r
120     jPanel1.add(close);\r
121     jPanel3.add(jPanel2, java.awt.BorderLayout.WEST);\r
122     jPanel2.add(database);\r
123     jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER);\r
124     jPanel3.add(jLabel1, java.awt.BorderLayout.NORTH);\r
125     this.add(jPanel1, java.awt.BorderLayout.SOUTH);\r
126     this.add(jPanel3, java.awt.BorderLayout.CENTER);\r
127     jScrollPane1.getViewport().add(textArea);\r
128 \r
129   }\r
130 \r
131   JComboBox database = new JComboBox();\r
132   JLabel jLabel1 = new JLabel();\r
133   JButton ok = new JButton();\r
134   JButton close = new JButton();\r
135   JPanel jPanel1 = new JPanel();\r
136   JTextArea textArea = new JTextArea();\r
137   JScrollPane jScrollPane1 = new JScrollPane();\r
138   JPanel jPanel2 = new JPanel();\r
139   JPanel jPanel3 = new JPanel();\r
140   BorderLayout borderLayout1 = new BorderLayout();\r
141   BorderLayout borderLayout2 = new BorderLayout();\r
142   public void close_actionPerformed(ActionEvent e)\r
143   {\r
144     try\r
145     {\r
146       frame.setClosed(true);\r
147     }\r
148     catch (Exception ex)\r
149     {}\r
150   }\r
151 \r
152   public void ok_actionPerformed()\r
153   {\r
154     database.setEnabled(false);\r
155     textArea.setEnabled(false);\r
156     ok.setEnabled(false);\r
157     close.setEnabled(false);\r
158 \r
159     Thread worker = new Thread(this);\r
160     worker.start();\r
161   }\r
162 \r
163   private void resetDialog()\r
164   {\r
165     database.setEnabled(true);\r
166     textArea.setEnabled(true);\r
167     ok.setEnabled(true);\r
168     close.setEnabled(true);\r
169   }\r
170 \r
171   public void run()\r
172   {\r
173     String error = "";\r
174     if (database.getSelectedItem().equals(noDbSelected))\r
175     {\r
176       error += "Please select the source database\n";\r
177     }\r
178     com.stevesoft.pat.Regex empty = new com.stevesoft.pat.Regex("\\s+", "");\r
179     textArea.setText(empty.replaceAll(textArea.getText()));\r
180     if (textArea.getText().length() == 0)\r
181     {\r
182       error += "Please enter a (semi-colon separated list of) database id(s)";\r
183     }\r
184     if (error.length() > 0)\r
185     {\r
186       showErrorMessage(error);\r
187       resetDialog();\r
188       return;\r
189     }\r
190 \r
191     result = new StringBuffer();\r
192     if (database.getSelectedItem().equals("Uniprot"))\r
193     {\r
194       getUniprotFile(textArea.getText());\r
195     }\r
196     else if (database.getSelectedItem().equals("EMBL")\r
197         || database.getSelectedItem().equals("EMBLCDS"))\r
198     {\r
199       String DBRefSource = database.getSelectedItem().equals("EMBLCDS")\r
200       ? jalview.datamodel.DBRefSource.EMBLCDS\r
201           : jalview.datamodel.DBRefSource.EMBL;\r
202 \r
203       StringTokenizer st = new StringTokenizer(textArea.getText(), ";");\r
204       SequenceI[] seqs = null;\r
205       while(st.hasMoreTokens())\r
206       {\r
207         EBIFetchClient dbFetch = new EBIFetchClient();\r
208 \r
209         File reply = dbFetch.fetchDataAsFile(\r
210             database.getSelectedItem().toString().toLowerCase(\r
211             ) + ":" + st.nextToken(),\r
212             "emblxml",null);\r
213 \r
214         jalview.datamodel.xdb.embl.EmblFile efile=null;\r
215         if (reply != null && reply.exists())\r
216         {\r
217           efile = jalview.datamodel.xdb.embl.EmblFile.getEmblFile(reply);\r
218         }\r
219         if (efile!=null) {\r
220           for (Iterator i=efile.getEntries().iterator(); i.hasNext(); ) {\r
221             EmblEntry entry = (EmblEntry) i.next();\r
222             SequenceI[] seqparts = entry.getSequences(false,true, DBRefSource);\r
223             if (seqparts!=null) {\r
224               SequenceI[] newseqs = null;\r
225               int si=0;\r
226               if (seqs==null) {\r
227                 newseqs = new SequenceI[seqparts.length];\r
228               } else {\r
229                 newseqs  = new SequenceI[seqs.length+seqparts.length];\r
230 \r
231                 for (;si<seqs.length; si++) {\r
232                   newseqs[si] = seqs[si];\r
233                   seqs[si] = null;\r
234                 }\r
235               }\r
236               for (int j=0;j<seqparts.length; si++, j++) {\r
237                 newseqs[si] = seqparts[j].deriveSequence(); // place DBReferences on dataset and refer\r
238               }\r
239               seqs=newseqs;\r
240 \r
241             }\r
242           }\r
243         } else {\r
244           result=null;\r
245         }\r
246       }\r
247       if (seqs!=null && seqs.length>0) {\r
248         if (parseResult(new Alignment(seqs), null, null)!=null)\r
249           result.append("# Successfully parsed the "+database.getSelectedItem()+" Queries into an Alignment");\r
250       }\r
251     }\r
252     else if (database.getSelectedItem().equals("PDB"))\r
253     {\r
254       StringTokenizer qset = new StringTokenizer(textArea.getText(), ";");\r
255       String query;\r
256       SequenceI[] seqs = null;\r
257       while (qset.hasMoreTokens() && ((query = qset.nextToken())!=null))\r
258       {\r
259         SequenceI[] seqparts = getPDBFile(query.toUpperCase());\r
260         if (seqparts != null)\r
261         {\r
262           if (seqs == null)\r
263           {\r
264             seqs = seqparts;\r
265           }\r
266           else\r
267           {\r
268             SequenceI[] newseqs = new SequenceI[seqs.length+seqparts.length];\r
269             int i=0;\r
270             for (; i < seqs.length; i++)\r
271             {\r
272               newseqs[i] = seqs[i];\r
273               seqs[i] = null;\r
274             }\r
275             for (int j=0;j<seqparts.length; i++, j++)\r
276             {\r
277               newseqs[i] = seqparts[j];\r
278             }\r
279             seqs=newseqs;\r
280           }\r
281           result.append("# Success for "+query.toUpperCase()+"\n");\r
282         }\r
283       }\r
284       if (seqs != null && seqs.length > 0)\r
285       {\r
286         if (parseResult(new Alignment(seqs), null, null)!=null)\r
287         {\r
288           result.append(\r
289           "# Successfully parsed the PDB File Queries into an Alignment");\r
290         }\r
291       }\r
292     }\r
293     else if( database.getSelectedItem().equals("PFAM"))\r
294     {\r
295       try\r
296       {\r
297         result.append(new FastaFile(\r
298             "http://www.sanger.ac.uk/cgi-bin/Pfam/getalignment.pl?format=fal&acc="\r
299             +  textArea.getText().toUpperCase(), "URL").print()\r
300         );\r
301 \r
302         if(result.length()>0)\r
303         {\r
304           parseResult( result.toString(), textArea.getText().toUpperCase() );\r
305         }\r
306 \r
307       }\r
308       catch (java.io.IOException ex)\r
309       {\r
310         result = null;\r
311       }\r
312     }\r
313 \r
314     if (result == null || result.length() == 0)\r
315     {\r
316       showErrorMessage("Error retrieving " + textArea.getText()\r
317           + " from " + database.getSelectedItem());\r
318     }\r
319 \r
320     resetDialog();\r
321     return;\r
322   }\r
323 \r
324   void getUniprotFile(String id)\r
325   {\r
326     EBIFetchClient ebi = new EBIFetchClient();\r
327     File file = ebi.fetchDataAsFile("uniprot:" + id, "xml", null);\r
328 \r
329     DBRefFetcher dbref = new DBRefFetcher();\r
330     Vector entries = dbref.getUniprotEntries(file);\r
331 \r
332     if (entries != null)\r
333     {\r
334       //First, make the new sequences\r
335       Enumeration en = entries.elements();\r
336       while (en.hasMoreElements())\r
337       {\r
338         UniprotEntry entry = (UniprotEntry) en.nextElement();\r
339 \r
340         StringBuffer name = new StringBuffer(">UniProt/Swiss-Prot");\r
341         Enumeration en2 = entry.getAccession().elements();\r
342         while (en2.hasMoreElements())\r
343         {\r
344           name.append("|");\r
345           name.append(en2.nextElement());\r
346         }\r
347         en2 = entry.getName().elements();\r
348         while (en2.hasMoreElements())\r
349         {\r
350           name.append("|");\r
351           name.append(en2.nextElement());\r
352         }\r
353 \r
354         if (entry.getProtein() != null)\r
355         {\r
356           name.append(" " + entry.getProtein().getName().elementAt(0));\r
357         }\r
358 \r
359         result.append(name + "\n" + entry.getUniprotSequence().getContent() +\r
360         "\n");\r
361 \r
362       }\r
363 \r
364       //Then read in the features and apply them to the dataset\r
365       Alignment al = parseResult(result.toString(), null);\r
366       for (int i = 0; i < entries.size(); i++)\r
367       {\r
368         UniprotEntry entry = (UniprotEntry) entries.elementAt(i);\r
369         Enumeration e = entry.getDbReference().elements();\r
370         Vector onlyPdbEntries = new Vector();\r
371         while (e.hasMoreElements())\r
372         {\r
373           PDBEntry pdb = (PDBEntry) e.nextElement();\r
374           if (!pdb.getType().equals("PDB"))\r
375           {\r
376             continue;\r
377           }\r
378 \r
379           onlyPdbEntries.addElement(pdb);\r
380         }\r
381 \r
382         Enumeration en2 = entry.getAccession().elements();\r
383         while (en2.hasMoreElements())\r
384         {\r
385           al.getSequenceAt(i).getDatasetSequence().addDBRef(new DBRefEntry(\r
386               DBRefSource.UNIPROT,\r
387               "0",\r
388               en2.nextElement().toString()));\r
389         }\r
390 \r
391 \r
392 \r
393 \r
394         al.getSequenceAt(i).getDatasetSequence().setPDBId(onlyPdbEntries);\r
395         if (entry.getFeature() != null)\r
396         {\r
397           e = entry.getFeature().elements();\r
398           while (e.hasMoreElements())\r
399           {\r
400             SequenceFeature sf = (SequenceFeature) e.nextElement();\r
401             sf.setFeatureGroup("Uniprot");\r
402             al.getSequenceAt(i).getDatasetSequence().addSequenceFeature( sf );\r
403           }\r
404         }\r
405       }\r
406     }\r
407   }\r
408 \r
409   SequenceI[] getPDBFile(String id)\r
410   {\r
411     Vector result = new Vector();\r
412     String chain = null;\r
413     if (id.indexOf(":") > -1)\r
414     {\r
415       chain = id.substring(id.indexOf(":") + 1);\r
416       id = id.substring(0, id.indexOf(":"));\r
417     }\r
418 \r
419     EBIFetchClient ebi = new EBIFetchClient();\r
420     String file = ebi.fetchDataAsFile("pdb:" + id, "pdb", "raw").\r
421     getAbsolutePath();\r
422     if (file == null)\r
423     {\r
424       return null;\r
425     }\r
426     try\r
427     {\r
428       PDBfile pdbfile = new PDBfile(file, jalview.io.AppletFormatAdapter.FILE);\r
429       for (int i = 0; i < pdbfile.chains.size(); i++)\r
430       {\r
431         if (chain == null ||\r
432             ( (PDBChain) pdbfile.chains.elementAt(i)).id.\r
433             toUpperCase().equals(chain))\r
434         {\r
435           PDBChain pdbchain = (PDBChain) pdbfile.chains.elementAt(i);\r
436           // Get the Chain's Sequence - who's dataset includes any special features added from the PDB file\r
437           SequenceI sq = pdbchain.sequence;\r
438           // Specially formatted name for the PDB chain sequences retrieved from the PDB\r
439           sq.setName("PDB|"+id+"|"+sq.getName());\r
440           // Might need to add more metadata to the PDBEntry object\r
441           // like below\r
442           /*\r
443            * PDBEntry entry = new PDBEntry();\r
444             // Construct the PDBEntry\r
445             entry.setId(id);\r
446             if (entry.getProperty() == null)\r
447                 entry.setProperty(new Hashtable());\r
448             entry.getProperty().put("chains",\r
449                         pdbchain.id\r
450                         + "=" + sq.getStart()\r
451                         + "-" + sq.getEnd());\r
452             sq.getDatasetSequence().addPDBId(entry);\r
453            */\r
454           // Add PDB DB Refs\r
455           // We make a DBRefEtntry because we have obtained the PDB file from a verifiable source\r
456           // JBPNote - PDB DBRefEntry should also carry the chain and mapping information\r
457           DBRefEntry dbentry = new DBRefEntry(jalview.datamodel.DBRefSource.PDB,\r
458               "0", id + pdbchain.id);\r
459           sq.addDBRef(dbentry);\r
460           // and add seuqence to the retrieved set\r
461           result.addElement(sq.deriveSequence());\r
462         }\r
463       }\r
464 \r
465       if (result.size() < 1)\r
466       {\r
467         throw new Exception("WsDBFetch for PDB id resulted in zero result size");\r
468       }\r
469     }\r
470     catch (Exception ex) // Problem parsing PDB file\r
471     {\r
472       jalview.bin.Cache.log.warn("Exception when retrieving " +\r
473           textArea.getText() + " from " +\r
474           database.getSelectedItem(), ex);\r
475       return null;\r
476     }\r
477 \r
478 \r
479     SequenceI[] results = new SequenceI[result.size()];\r
480     for (int i = 0, j = result.size(); i < j; i++)\r
481     {\r
482       results[i] = (SequenceI) result.elementAt(i);\r
483       result.setElementAt(null,i);\r
484     }\r
485     return results;\r
486   }\r
487   Alignment parseResult(String result, String title)\r
488   {\r
489     String format = new IdentifyFile().Identify(result, "Paste");\r
490     Alignment sequences = null;\r
491     if (FormatAdapter.isValidFormat(format))\r
492     {\r
493       sequences = null;\r
494       try\r
495       {\r
496         sequences = new FormatAdapter().readFile(result.toString(), "Paste",\r
497             format);\r
498       }\r
499       catch (Exception ex)\r
500       {}\r
501 \r
502       if (sequences!=null)\r
503       {\r
504         return parseResult(sequences, title, format);\r
505       }\r
506     }\r
507     else\r
508     {\r
509       showErrorMessage("Error retrieving " + textArea.getText()\r
510           + " from " + database.getSelectedItem());\r
511     }\r
512 \r
513     return null;\r
514   }\r
515 \r
516   Alignment parseResult(Alignment al, String title, String currentFileFormat)\r
517   {\r
518 \r
519     if (al != null && al.getHeight() > 0)\r
520     {\r
521       if (alignFrame == null)\r
522       {\r
523         AlignFrame af = new AlignFrame(al,\r
524             AlignFrame.DEFAULT_WIDTH,\r
525             AlignFrame.DEFAULT_HEIGHT);\r
526         if (currentFileFormat!=null)\r
527         {\r
528           af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT FORMAT FOR NON-FormatAdapter Sourced Alignments?\r
529         }\r
530 \r
531         if(title==null)\r
532         {\r
533           title = "Retrieved from " + database.getSelectedItem();\r
534         }\r
535 \r
536         Desktop.addInternalFrame(af,\r
537             title,\r
538             AlignFrame.DEFAULT_WIDTH,\r
539             AlignFrame.DEFAULT_HEIGHT);\r
540 \r
541         af.statusBar.setText("Successfully pasted alignment file");\r
542 \r
543         try\r
544         {\r
545           af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));\r
546         }\r
547         catch (Exception ex)\r
548         {}\r
549       }\r
550       else\r
551       {\r
552         for (int i = 0; i < al.getHeight(); i++)\r
553         {\r
554           alignFrame.viewport.alignment.addSequence(al.getSequenceAt(i)); // this also creates dataset sequence entries\r
555         }\r
556         alignFrame.viewport.setEndSeq(alignFrame.viewport.alignment.\r
557             getHeight());\r
558         alignFrame.viewport.alignment.getWidth();\r
559         alignFrame.viewport.firePropertyChange("alignment", null,\r
560             alignFrame.viewport.\r
561             getAlignment().getSequences());\r
562       }\r
563     }\r
564     return al;\r
565   }\r
566 \r
567   void showErrorMessage(final String error)\r
568   {\r
569     resetDialog();\r
570     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
571     {\r
572       public void run()\r
573       {\r
574         JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
575             error, "Error Retrieving Data",\r
576             JOptionPane.WARNING_MESSAGE);\r
577       }\r
578     });\r
579   }\r
580 }\r
581 \r