Allow expansion of textarea for many sequence input
[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         System.out.println(e.getKeyCode()+" "+KeyEvent.VK_ENTER);\r
114         if(e.getKeyCode()==KeyEvent.VK_ENTER)\r
115           ok_actionPerformed();\r
116       }\r
117     });\r
118     jPanel3.setLayout(borderLayout1);\r
119     borderLayout1.setVgap(5);\r
120     jPanel1.add(ok);\r
121     jPanel1.add(close);\r
122     jPanel3.add(jPanel2, java.awt.BorderLayout.WEST);\r
123     jPanel2.add(database);\r
124     jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER);\r
125     jPanel3.add(jLabel1, java.awt.BorderLayout.NORTH);\r
126     this.add(jPanel1, java.awt.BorderLayout.SOUTH);\r
127     this.add(jPanel3, java.awt.BorderLayout.CENTER);\r
128     jScrollPane1.getViewport().add(textArea);\r
129 \r
130   }\r
131 \r
132   JComboBox database = new JComboBox();\r
133   JLabel jLabel1 = new JLabel();\r
134   JButton ok = new JButton();\r
135   JButton close = new JButton();\r
136   JPanel jPanel1 = new JPanel();\r
137   JTextArea textArea = new JTextArea();\r
138   JScrollPane jScrollPane1 = new JScrollPane();\r
139   JPanel jPanel2 = new JPanel();\r
140   JPanel jPanel3 = new JPanel();\r
141   BorderLayout borderLayout1 = new BorderLayout();\r
142   BorderLayout borderLayout2 = new BorderLayout();\r
143   public void close_actionPerformed(ActionEvent e)\r
144   {\r
145     try\r
146     {\r
147       frame.setClosed(true);\r
148     }\r
149     catch (Exception ex)\r
150     {}\r
151   }\r
152 \r
153   public void ok_actionPerformed()\r
154   {\r
155     database.setEnabled(false);\r
156     textArea.setEnabled(false);\r
157     ok.setEnabled(false);\r
158     close.setEnabled(false);\r
159 \r
160     Thread worker = new Thread(this);\r
161     worker.start();\r
162   }\r
163 \r
164   private void resetDialog()\r
165   {\r
166     database.setEnabled(true);\r
167     textArea.setEnabled(true);\r
168     ok.setEnabled(true);\r
169     close.setEnabled(true);\r
170   }\r
171 \r
172   public void run()\r
173   {\r
174     String error = "";\r
175     if (database.getSelectedItem().equals(noDbSelected))\r
176     {\r
177       error += "Please select the source database\n";\r
178     }\r
179     com.stevesoft.pat.Regex empty = new com.stevesoft.pat.Regex("\\s+", "");\r
180     textArea.setText(empty.replaceAll(textArea.getText()));\r
181     if (textArea.getText().length() == 0)\r
182     {\r
183       error += "Please enter a (semi-colon separated list of) database id(s)";\r
184     }\r
185     if (error.length() > 0)\r
186     {\r
187       showErrorMessage(error);\r
188       resetDialog();\r
189       return;\r
190     }\r
191 \r
192     result = new StringBuffer();\r
193     if (database.getSelectedItem().equals("Uniprot"))\r
194     {\r
195       getUniprotFile(textArea.getText());\r
196     }\r
197     else if (database.getSelectedItem().equals("EMBL")\r
198         || database.getSelectedItem().equals("EMBLCDS"))\r
199     {\r
200       String DBRefSource = database.getSelectedItem().equals("EMBLCDS")\r
201       ? jalview.datamodel.DBRefSource.EMBLCDS\r
202           : jalview.datamodel.DBRefSource.EMBL;\r
203 \r
204       StringTokenizer st = new StringTokenizer(textArea.getText(), ";");\r
205       SequenceI[] seqs = null;\r
206       while(st.hasMoreTokens())\r
207       {\r
208         EBIFetchClient dbFetch = new EBIFetchClient();\r
209 \r
210         File reply = dbFetch.fetchDataAsFile(\r
211             database.getSelectedItem().toString().toLowerCase(\r
212             ) + ":" + st.nextToken(),\r
213             "emblxml",null);\r
214 \r
215         jalview.datamodel.xdb.embl.EmblFile efile=null;\r
216         if (reply != null && reply.exists())\r
217         {\r
218           efile = jalview.datamodel.xdb.embl.EmblFile.getEmblFile(reply);\r
219         }\r
220         if (efile!=null) {\r
221           for (Iterator i=efile.getEntries().iterator(); i.hasNext(); ) {\r
222             EmblEntry entry = (EmblEntry) i.next();\r
223             SequenceI[] seqparts = entry.getSequences(false,true, DBRefSource);\r
224             if (seqparts!=null) {\r
225               SequenceI[] newseqs = null;\r
226               int si=0;\r
227               if (seqs==null) {\r
228                 newseqs = new SequenceI[seqparts.length];\r
229               } else {\r
230                 newseqs  = new SequenceI[seqs.length+seqparts.length];\r
231 \r
232                 for (;si<seqs.length; si++) {\r
233                   newseqs[si] = seqs[si];\r
234                   seqs[si] = null;\r
235                 }\r
236               }\r
237               for (int j=0;j<seqparts.length; si++, j++) {\r
238                 newseqs[si] = seqparts[j].deriveSequence(); // place DBReferences on dataset and refer\r
239               }\r
240               seqs=newseqs;\r
241 \r
242             }\r
243           }\r
244         } else {\r
245           result=null;\r
246         }\r
247       }\r
248       if (seqs!=null && seqs.length>0) {\r
249         if (parseResult(new Alignment(seqs), null, null)!=null)\r
250           result.append("# Successfully parsed the "+database.getSelectedItem()+" Queries into an Alignment");\r
251       }\r
252     }\r
253     else if (database.getSelectedItem().equals("PDB"))\r
254     {\r
255       StringTokenizer qset = new StringTokenizer(textArea.getText(), ";");\r
256       String query;\r
257       SequenceI[] seqs = null;\r
258       while (qset.hasMoreTokens() && ((query = qset.nextToken())!=null))\r
259       {\r
260         SequenceI[] seqparts = getPDBFile(query.toUpperCase());\r
261         if (seqparts != null)\r
262         {\r
263           if (seqs == null)\r
264           {\r
265             seqs = seqparts;\r
266           }\r
267           else\r
268           {\r
269             SequenceI[] newseqs = new SequenceI[seqs.length+seqparts.length];\r
270             int i=0;\r
271             for (; i < seqs.length; i++)\r
272             {\r
273               newseqs[i] = seqs[i];\r
274               seqs[i] = null;\r
275             }\r
276             for (int j=0;j<seqparts.length; i++, j++)\r
277             {\r
278               newseqs[i] = seqparts[j];\r
279             }\r
280             seqs=newseqs;\r
281           }\r
282           result.append("# Success for "+query.toUpperCase()+"\n");\r
283         }\r
284       }\r
285       if (seqs != null && seqs.length > 0)\r
286       {\r
287         if (parseResult(new Alignment(seqs), null, null)!=null)\r
288         {\r
289           result.append(\r
290           "# Successfully parsed the PDB File Queries into an Alignment");\r
291         }\r
292       }\r
293     }\r
294     else if( database.getSelectedItem().equals("PFAM"))\r
295     {\r
296       try\r
297       {\r
298         result.append(new FastaFile(\r
299             "http://www.sanger.ac.uk/cgi-bin/Pfam/getalignment.pl?format=fal&acc="\r
300             +  textArea.getText().toUpperCase(), "URL").print()\r
301         );\r
302 \r
303         if(result.length()>0)\r
304         {\r
305           parseResult( result.toString(), textArea.getText().toUpperCase() );\r
306         }\r
307 \r
308       }\r
309       catch (java.io.IOException ex)\r
310       {\r
311         result = null;\r
312       }\r
313     }\r
314 \r
315     if (result == null || result.length() == 0)\r
316     {\r
317       showErrorMessage("Error retrieving " + textArea.getText()\r
318           + " from " + database.getSelectedItem());\r
319     }\r
320 \r
321     resetDialog();\r
322     return;\r
323   }\r
324 \r
325   void getUniprotFile(String id)\r
326   {\r
327     EBIFetchClient ebi = new EBIFetchClient();\r
328     File file = ebi.fetchDataAsFile("uniprot:" + id, "xml", null);\r
329 \r
330     DBRefFetcher dbref = new DBRefFetcher();\r
331     Vector entries = dbref.getUniprotEntries(file);\r
332 \r
333     if (entries != null)\r
334     {\r
335       //First, make the new sequences\r
336       Enumeration en = entries.elements();\r
337       while (en.hasMoreElements())\r
338       {\r
339         UniprotEntry entry = (UniprotEntry) en.nextElement();\r
340 \r
341         StringBuffer name = new StringBuffer(">UniProt/Swiss-Prot");\r
342         Enumeration en2 = entry.getAccession().elements();\r
343         while (en2.hasMoreElements())\r
344         {\r
345           name.append("|");\r
346           name.append(en2.nextElement());\r
347         }\r
348         en2 = entry.getName().elements();\r
349         while (en2.hasMoreElements())\r
350         {\r
351           name.append("|");\r
352           name.append(en2.nextElement());\r
353         }\r
354 \r
355         if (entry.getProtein() != null)\r
356         {\r
357           name.append(" " + entry.getProtein().getName().elementAt(0));\r
358         }\r
359 \r
360         result.append(name + "\n" + entry.getUniprotSequence().getContent() +\r
361         "\n");\r
362 \r
363       }\r
364 \r
365       //Then read in the features and apply them to the dataset\r
366       Alignment al = parseResult(result.toString(), null);\r
367       for (int i = 0; i < entries.size(); i++)\r
368       {\r
369         UniprotEntry entry = (UniprotEntry) entries.elementAt(i);\r
370         Enumeration e = entry.getDbReference().elements();\r
371         Vector onlyPdbEntries = new Vector();\r
372         while (e.hasMoreElements())\r
373         {\r
374           PDBEntry pdb = (PDBEntry) e.nextElement();\r
375           if (!pdb.getType().equals("PDB"))\r
376           {\r
377             continue;\r
378           }\r
379 \r
380           onlyPdbEntries.addElement(pdb);\r
381         }\r
382 \r
383         Enumeration en2 = entry.getAccession().elements();\r
384         while (en2.hasMoreElements())\r
385         {\r
386           al.getSequenceAt(i).getDatasetSequence().addDBRef(new DBRefEntry(\r
387               DBRefSource.UNIPROT,\r
388               "0",\r
389               en2.nextElement().toString()));\r
390         }\r
391 \r
392 \r
393 \r
394 \r
395         al.getSequenceAt(i).getDatasetSequence().setPDBId(onlyPdbEntries);\r
396         if (entry.getFeature() != null)\r
397         {\r
398           e = entry.getFeature().elements();\r
399           while (e.hasMoreElements())\r
400           {\r
401             SequenceFeature sf = (SequenceFeature) e.nextElement();\r
402             sf.setFeatureGroup("Uniprot");\r
403             al.getSequenceAt(i).getDatasetSequence().addSequenceFeature( sf );\r
404           }\r
405         }\r
406       }\r
407     }\r
408   }\r
409 \r
410   SequenceI[] getPDBFile(String id)\r
411   {\r
412     Vector result = new Vector();\r
413     String chain = null;\r
414     if (id.indexOf(":") > -1)\r
415     {\r
416       chain = id.substring(id.indexOf(":") + 1);\r
417       id = id.substring(0, id.indexOf(":"));\r
418     }\r
419 \r
420     EBIFetchClient ebi = new EBIFetchClient();\r
421     String file = ebi.fetchDataAsFile("pdb:" + id, "pdb", "raw").\r
422     getAbsolutePath();\r
423     if (file == null)\r
424     {\r
425       return null;\r
426     }\r
427     try\r
428     {\r
429       PDBfile pdbfile = new PDBfile(file, jalview.io.AppletFormatAdapter.FILE);\r
430       for (int i = 0; i < pdbfile.chains.size(); i++)\r
431       {\r
432         if (chain == null ||\r
433             ( (PDBChain) pdbfile.chains.elementAt(i)).id.\r
434             toUpperCase().equals(chain))\r
435         {\r
436           PDBChain pdbchain = (PDBChain) pdbfile.chains.elementAt(i);\r
437           // Get the Chain's Sequence - who's dataset includes any special features added from the PDB file\r
438           SequenceI sq = pdbchain.sequence;\r
439           // Specially formatted name for the PDB chain sequences retrieved from the PDB\r
440           sq.setName("PDB|"+id+"|"+sq.getName());\r
441           // Might need to add more metadata to the PDBEntry object\r
442           // like below\r
443           /*\r
444            * PDBEntry entry = new PDBEntry();\r
445             // Construct the PDBEntry\r
446             entry.setId(id);\r
447             if (entry.getProperty() == null)\r
448                 entry.setProperty(new Hashtable());\r
449             entry.getProperty().put("chains",\r
450                         pdbchain.id\r
451                         + "=" + sq.getStart()\r
452                         + "-" + sq.getEnd());\r
453             sq.getDatasetSequence().addPDBId(entry);\r
454            */\r
455           // Add PDB DB Refs\r
456           // We make a DBRefEtntry because we have obtained the PDB file from a verifiable source\r
457           // JBPNote - PDB DBRefEntry should also carry the chain and mapping information\r
458           DBRefEntry dbentry = new DBRefEntry(jalview.datamodel.DBRefSource.PDB,\r
459               "0", id + pdbchain.id);\r
460           sq.addDBRef(dbentry);\r
461           // and add seuqence to the retrieved set\r
462           result.addElement(sq.deriveSequence());\r
463         }\r
464       }\r
465 \r
466       if (result.size() < 1)\r
467       {\r
468         throw new Exception("WsDBFetch for PDB id resulted in zero result size");\r
469       }\r
470     }\r
471     catch (Exception ex) // Problem parsing PDB file\r
472     {\r
473       jalview.bin.Cache.log.warn("Exception when retrieving " +\r
474           textArea.getText() + " from " +\r
475           database.getSelectedItem(), ex);\r
476       return null;\r
477     }\r
478 \r
479 \r
480     SequenceI[] results = new SequenceI[result.size()];\r
481     for (int i = 0, j = result.size(); i < j; i++)\r
482     {\r
483       results[i] = (SequenceI) result.elementAt(i);\r
484       result.setElementAt(null,i);\r
485     }\r
486     return results;\r
487   }\r
488   Alignment parseResult(String result, String title)\r
489   {\r
490     String format = new IdentifyFile().Identify(result, "Paste");\r
491     Alignment sequences = null;\r
492     if (FormatAdapter.isValidFormat(format))\r
493     {\r
494       sequences = null;\r
495       try\r
496       {\r
497         sequences = new FormatAdapter().readFile(result.toString(), "Paste",\r
498             format);\r
499       }\r
500       catch (Exception ex)\r
501       {}\r
502 \r
503       if (sequences!=null)\r
504       {\r
505         return parseResult(sequences, title, format);\r
506       }\r
507     }\r
508     else\r
509     {\r
510       showErrorMessage("Error retrieving " + textArea.getText()\r
511           + " from " + database.getSelectedItem());\r
512     }\r
513 \r
514     return null;\r
515   }\r
516 \r
517   Alignment parseResult(Alignment al, String title, String currentFileFormat)\r
518   {\r
519 \r
520     if (al != null && al.getHeight() > 0)\r
521     {\r
522       if (alignFrame == null)\r
523       {\r
524         AlignFrame af = new AlignFrame(al,\r
525             AlignFrame.DEFAULT_WIDTH,\r
526             AlignFrame.DEFAULT_HEIGHT);\r
527         if (currentFileFormat!=null)\r
528         {\r
529           af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT FORMAT FOR NON-FormatAdapter Sourced Alignments?\r
530         }\r
531 \r
532         if(title==null)\r
533         {\r
534           title = "Retrieved from " + database.getSelectedItem();\r
535         }\r
536 \r
537         Desktop.addInternalFrame(af,\r
538             title,\r
539             AlignFrame.DEFAULT_WIDTH,\r
540             AlignFrame.DEFAULT_HEIGHT);\r
541 \r
542         af.statusBar.setText("Successfully pasted alignment file");\r
543 \r
544         try\r
545         {\r
546           af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));\r
547         }\r
548         catch (Exception ex)\r
549         {}\r
550       }\r
551       else\r
552       {\r
553         for (int i = 0; i < al.getHeight(); i++)\r
554         {\r
555           alignFrame.viewport.alignment.addSequence(al.getSequenceAt(i)); // this also creates dataset sequence entries\r
556         }\r
557         alignFrame.viewport.setEndSeq(alignFrame.viewport.alignment.\r
558             getHeight());\r
559         alignFrame.viewport.alignment.getWidth();\r
560         alignFrame.viewport.firePropertyChange("alignment", null,\r
561             alignFrame.viewport.\r
562             getAlignment().getSequences());\r
563       }\r
564     }\r
565     return al;\r
566   }\r
567 \r
568   void showErrorMessage(final String error)\r
569   {\r
570     resetDialog();\r
571     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
572     {\r
573       public void run()\r
574       {\r
575         JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
576             error, "Error Retrieving Data",\r
577             JOptionPane.WARNING_MESSAGE);\r
578       }\r
579     });\r
580   }\r
581 }\r
582 \r