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