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