JAL-3851 throwaway code
[jalview.git] / src / jalview / gui / SequenceFetcher.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import java.awt.BorderLayout;
24 import java.awt.Font;
25 import java.awt.event.ActionEvent;
26 import java.awt.event.ActionListener;
27 import java.awt.event.KeyAdapter;
28 import java.awt.event.KeyEvent;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Map;
35
36 import javax.swing.JButton;
37 import javax.swing.JCheckBox;
38 import javax.swing.JComboBox;
39 import javax.swing.JInternalFrame;
40 import javax.swing.JLabel;
41 import javax.swing.JPanel;
42 import javax.swing.JScrollPane;
43 import javax.swing.JTextArea;
44 import javax.swing.SwingConstants;
45
46 import jalview.api.FeatureSettingsModelI;
47 import jalview.bin.Cache;
48 import jalview.datamodel.AlignmentI;
49 import jalview.datamodel.DBRefEntry;
50 import jalview.datamodel.SequenceI;
51 import jalview.fts.core.GFTSPanel;
52 import jalview.fts.service.pdb.PDBFTSPanel;
53 import jalview.fts.service.uniprot.UniprotFTSPanel;
54 import jalview.io.FileFormatI;
55 import jalview.io.gff.SequenceOntologyI;
56 import jalview.util.DBRefUtils;
57 import jalview.util.MessageManager;
58 import jalview.util.Platform;
59 import jalview.ws.seqfetcher.DbSourceProxy;
60
61 /**
62  * A panel where the use may choose a database source, and enter one or more
63  * accessions, to retrieve entries from the database.
64  * <p>
65  * If the selected source is Uniprot or PDB, a free text search panel is opened
66  * instead to perform the search and selection.
67  */
68 public class SequenceFetcher extends JPanel implements Runnable
69 {
70   private static jalview.ws.SequenceFetcher sfetch = null;
71
72   JLabel exampleAccession;
73
74   JComboBox<String> database;
75
76   JCheckBox replacePunctuation;
77
78   JButton okBtn;
79
80   JButton exampleBtn;
81
82   JButton closeBtn;
83
84   JButton backBtn;
85
86   JTextArea textArea;
87
88   JInternalFrame frame;
89
90   IProgressIndicator guiWindow;
91
92   AlignFrame alignFrame;
93
94   GFTSPanel parentSearchPanel;
95
96   IProgressIndicator progressIndicator;
97
98   volatile boolean _isConstructing = false;
99
100   private boolean closeDialog = false;
101
102   // set to true to close the fetch sequence dialog window after completion
103   public void closeDialog(boolean c)
104   {
105     closeDialog = c;
106   }
107
108   /**
109    * Returns the shared instance of the SequenceFetcher client
110    * 
111    * @return
112    */
113   public static jalview.ws.SequenceFetcher getSequenceFetcherSingleton()
114   {
115     if (sfetch == null)
116     {
117       sfetch = new jalview.ws.SequenceFetcher();
118     }
119     return sfetch;
120   }
121
122   /**
123    * Constructor given a client to receive any status or progress messages
124    * (currently either the Desktop, or an AlignFrame panel)
125    * 
126    * @param guiIndic
127    */
128   public SequenceFetcher(IProgressIndicator guiIndic)
129   {
130     this(guiIndic, null, null);
131   }
132
133   /**
134    * Constructor with specified database and accession(s) to retrieve
135    * 
136    * @param guiIndic
137    * @param selectedDb
138    * @param queryString
139    */
140   public SequenceFetcher(IProgressIndicator guiIndic,
141           final String selectedDb, final String queryString)
142   {
143     this.progressIndicator = guiIndic;
144     getSequenceFetcherSingleton();
145     this.guiWindow = progressIndicator;
146
147     if (progressIndicator instanceof AlignFrame)
148     {
149       alignFrame = (AlignFrame) progressIndicator;
150     }
151
152     jbInit(selectedDb);
153     textArea.setText(queryString);
154
155     frame = new JInternalFrame();
156     frame.setContentPane(this);
157     Desktop.addInternalFrame(frame, getFrameTitle(), true, 400,
158             Platform.isAMacAndNotJS() ? 240 : 180);
159   }
160
161   private String getFrameTitle()
162   {
163     return ((alignFrame == null)
164             ? MessageManager.getString("label.new_sequence_fetcher")
165             : MessageManager
166                     .getString("label.additional_sequence_fetcher"));
167   }
168
169   private void jbInit(String selectedDb)
170   {
171     this.setLayout(new BorderLayout());
172
173     database = new JComboBox<>();
174     database.setFont(JvSwingUtils.getLabelFont());
175     database.setPrototypeDisplayValue("ENSEMBLGENOMES   ");
176     String[] sources = new jalview.ws.SequenceFetcher().getSupportedDb();
177     Arrays.sort(sources, String.CASE_INSENSITIVE_ORDER);
178     database.addItem(MessageManager.getString("action.select_ddbb"));
179     for (String source : sources)
180     {
181       database.addItem(source);
182     }
183     database.setSelectedItem(selectedDb);
184     if (database.getSelectedIndex() == -1)
185     {
186       database.setSelectedIndex(0);
187     }
188     database.setMaximumRowCount(database.getItemCount());
189     database.addActionListener(new ActionListener()
190     {
191       @Override
192       public void actionPerformed(ActionEvent e)
193       {
194         String currentSelection = (String) database.getSelectedItem();
195         updateExampleQuery(currentSelection);
196
197         if ("pdb".equalsIgnoreCase(currentSelection))
198         {
199           frame.dispose();
200           new PDBFTSPanel(SequenceFetcher.this);
201         }
202         else if ("uniprot".equalsIgnoreCase(currentSelection))
203         {
204           frame.dispose();
205           new UniprotFTSPanel(SequenceFetcher.this);
206         }
207         else
208         {
209           otherSourceAction();
210         }
211       }
212     });
213
214     exampleAccession = new JLabel("");
215     exampleAccession.setFont(new Font("Verdana", Font.BOLD, 11));
216     JLabel jLabel1 = new JLabel(MessageManager
217             .getString("label.separate_multiple_accession_ids"));
218     jLabel1.setFont(new Font("Verdana", Font.ITALIC, 11));
219     jLabel1.setHorizontalAlignment(SwingConstants.LEFT);
220
221     replacePunctuation = new JCheckBox(
222             MessageManager.getString("label.replace_commas_semicolons"));
223     replacePunctuation.setHorizontalAlignment(SwingConstants.LEFT);
224     replacePunctuation.setFont(new Font("Verdana", Font.ITALIC, 11));
225     okBtn = new JButton(MessageManager.getString("action.ok"));
226     okBtn.addActionListener(new ActionListener()
227     {
228       @Override
229       public void actionPerformed(ActionEvent e)
230       {
231         ok_actionPerformed();
232       }
233     });
234     JButton clear = new JButton(MessageManager.getString("action.clear"));
235     clear.addActionListener(new ActionListener()
236     {
237       @Override
238       public void actionPerformed(ActionEvent e)
239       {
240         clear_actionPerformed();
241       }
242     });
243
244     exampleBtn = new JButton(MessageManager.getString("label.example"));
245     exampleBtn.addActionListener(new ActionListener()
246     {
247       @Override
248       public void actionPerformed(ActionEvent e)
249       {
250         example_actionPerformed();
251       }
252     });
253     closeBtn = new JButton(MessageManager.getString("action.cancel"));
254     closeBtn.addActionListener(new ActionListener()
255     {
256       @Override
257       public void actionPerformed(ActionEvent e)
258       {
259         close_actionPerformed(e);
260       }
261     });
262     backBtn = new JButton(MessageManager.getString("action.back"));
263     backBtn.addActionListener(new ActionListener()
264     {
265       @Override
266       public void actionPerformed(ActionEvent e)
267       {
268         parentSearchPanel.btn_back_ActionPerformed();
269       }
270     });
271     // back not visible unless embedded
272     backBtn.setVisible(false);
273
274     textArea = new JTextArea();
275     textArea.setFont(JvSwingUtils.getLabelFont());
276     textArea.setLineWrap(true);
277     textArea.addKeyListener(new KeyAdapter()
278     {
279       @Override
280       public void keyPressed(KeyEvent e)
281       {
282         if (e.getKeyCode() == KeyEvent.VK_ENTER)
283         {
284           ok_actionPerformed();
285         }
286       }
287     });
288
289     JPanel actionPanel = new JPanel();
290     actionPanel.add(backBtn);
291     actionPanel.add(exampleBtn);
292     actionPanel.add(clear);
293     actionPanel.add(okBtn);
294     actionPanel.add(closeBtn);
295
296     JPanel databasePanel = new JPanel();
297     databasePanel.setLayout(new BorderLayout());
298     databasePanel.add(database, BorderLayout.NORTH);
299     databasePanel.add(exampleAccession, BorderLayout.CENTER);
300     JPanel jPanel2a = new JPanel(new BorderLayout());
301     jPanel2a.add(jLabel1, BorderLayout.NORTH);
302     jPanel2a.add(replacePunctuation, BorderLayout.SOUTH);
303     databasePanel.add(jPanel2a, BorderLayout.SOUTH);
304
305     JPanel idsPanel = new JPanel();
306     idsPanel.setLayout(new BorderLayout(0, 5));
307     JScrollPane jScrollPane1 = new JScrollPane();
308     jScrollPane1.getViewport().add(textArea);
309     idsPanel.add(jScrollPane1, BorderLayout.CENTER);
310
311     this.add(actionPanel, BorderLayout.SOUTH);
312     this.add(idsPanel, BorderLayout.CENTER);
313     this.add(databasePanel, BorderLayout.NORTH);
314   }
315
316   /**
317    * Answers a semi-colon-delimited string with the example query or queries for
318    * the selected database
319    * 
320    * @param db
321    * @return
322    */
323   protected String getExampleQueries(String db)
324   {
325     StringBuilder sb = new StringBuilder();
326     HashSet<String> hs = new HashSet<>();
327     for (DbSourceProxy dbs : sfetch.getSourceProxy(db))
328     {
329       String tq = dbs.getTestQuery();
330       if (hs.add(tq)) // not a duplicate source
331       {
332         if (sb.length() > 0)
333         {
334           sb.append(";");
335         }
336         sb.append(tq);
337       }
338     }
339     return sb.toString();
340   }
341
342   /**
343    * Action on selecting a database other than Uniprot or PDB is to enable or
344    * disable 'Replace commas', and await input in the query field
345    */
346   protected void otherSourceAction()
347   {
348     try
349     {
350       String eq = exampleAccession.getText();
351       // TODO this should be a property of the SequenceFetcher whether commas
352       // are allowed in the IDs...
353
354       boolean enablePunct = !(eq != null && eq.indexOf(",") > -1);
355       replacePunctuation.setEnabled(enablePunct);
356
357     } catch (Exception ex)
358     {
359       exampleAccession.setText("");
360       replacePunctuation.setEnabled(true);
361     }
362     repaint();
363   }
364
365   /**
366    * Sets the text of the example query to incorporate the example accession
367    * provided by the selected database source
368    * 
369    * @param selectedDatabase
370    * @return
371    */
372   protected String updateExampleQuery(String selectedDatabase)
373   {
374     String eq = getExampleQueries(selectedDatabase);
375     exampleAccession.setText(MessageManager
376             .formatMessage("label.example_query_param", new String[]
377             { eq }));
378     return eq;
379   }
380
381   /**
382    * Action on clicking the 'Example' button is to write the example accession
383    * as the query text field value
384    */
385   protected void example_actionPerformed()
386   {
387     String eq = getExampleQueries((String) database.getSelectedItem());
388     textArea.setText(eq);
389     repaint();
390   }
391
392   /**
393    * Clears the query input field
394    */
395   protected void clear_actionPerformed()
396   {
397     textArea.setText("");
398     repaint();
399   }
400
401   /**
402    * Action on Close button is to close this frame, and also (if it is embedded
403    * in a search panel) to close the search panel
404    * 
405    * @param e
406    */
407   protected void close_actionPerformed(ActionEvent e)
408   {
409     try
410     {
411       frame.setClosed(true);
412       if (parentSearchPanel != null)
413       {
414         parentSearchPanel.btn_cancel_ActionPerformed();
415       }
416     } catch (Exception ex)
417     {
418     }
419   }
420
421   /**
422    * Action on OK is to start the fetch for entered accession(s)
423    */
424   public void ok_actionPerformed()
425   {
426     ok_actionPerformed(false);
427   }
428
429   public Thread ok_actionPerformed(boolean returnThread)
430   {
431     /*
432      * tidy inputs and check there is something to search for
433      */
434     String t0 = textArea.getText();
435     String text = t0.trim();
436     if (replacePunctuation.isEnabled() && replacePunctuation.isSelected())
437     {
438       text = text.replace(",", ";");
439     }
440     text = text.replaceAll("(\\s|[; ])+", ";");
441     if (!t0.equals(text))
442     {
443       textArea.setText(text);
444     }
445     if (text.isEmpty())
446     {
447       // todo i18n
448       showErrorMessage(
449               "Please enter a (semi-colon separated list of) database id(s)");
450       resetDialog();
451       return null;
452     }
453     if (database.getSelectedIndex() == 0)
454     {
455       // todo i18n
456       showErrorMessage("Please choose a database");
457       resetDialog();
458       return null;
459     }
460
461     exampleBtn.setEnabled(false);
462     textArea.setEnabled(false);
463     okBtn.setEnabled(false);
464     closeBtn.setEnabled(false);
465     backBtn.setEnabled(false);
466
467     Thread worker = new Thread(this);
468     worker.start();
469     return returnThread ? worker : null;
470   }
471
472   private void resetDialog()
473   {
474     exampleBtn.setEnabled(true);
475     textArea.setEnabled(true);
476     okBtn.setEnabled(true);
477     closeBtn.setEnabled(true);
478     backBtn.setEnabled(parentSearchPanel != null);
479   }
480
481   @Override
482   public void run()
483   {
484     boolean addToLast = false;
485     List<String> aresultq = new ArrayList<>();
486     List<String> presultTitle = new ArrayList<>();
487     List<AlignmentI> presult = new ArrayList<>();
488     List<AlignmentI> aresult = new ArrayList<>();
489     List<DbSourceProxy> sources = sfetch
490             .getSourceProxy((String) database.getSelectedItem());
491     Iterator<DbSourceProxy> proxies = sources.iterator();
492     String[] qries = textArea.getText().trim().split(";");
493     List<String> nextFetch = Arrays.asList(qries);
494     Iterator<String> en = Arrays.asList(new String[0]).iterator();
495     int nqueries = qries.length;
496
497     FeatureSettingsModelI preferredFeatureColours = null;
498     while (proxies.hasNext() && (en.hasNext() || nextFetch.size() > 0))
499     {
500       if (!en.hasNext() && nextFetch.size() > 0)
501       {
502         en = nextFetch.iterator();
503         nqueries = nextFetch.size();
504         // save the remaining queries in the original array
505         qries = nextFetch.toArray(new String[nqueries]);
506         nextFetch = new ArrayList<>();
507       }
508
509       DbSourceProxy proxy = proxies.next();
510       try
511       {
512         // update status
513         guiWindow.setProgressBar(MessageManager.formatMessage(
514                 "status.fetching_sequence_queries_from", new String[]
515                 { Integer.valueOf(nqueries).toString(),
516                     proxy.getDbName() }),
517                 Thread.currentThread().hashCode());
518         if (proxy.getMaximumQueryCount() == 1)
519         {
520           /*
521            * proxy only handles one accession id at a time
522            */
523           while (en.hasNext())
524           {
525             String acc = en.next();
526             if (!fetchSingleAccession(proxy, acc, aresultq, aresult))
527             {
528               nextFetch.add(acc);
529             }
530           }
531         }
532         else
533         {
534           /*
535            * proxy can fetch multiple accessions at one time
536            */
537           fetchMultipleAccessions(proxy, en, aresultq, aresult, nextFetch);
538         }
539       } catch (Exception e)
540       {
541         showErrorMessage("Error retrieving " + textArea.getText() + " from "
542                 + database.getSelectedItem());
543         // error
544         // +="Couldn't retrieve sequences from "+database.getSelectedItem();
545         System.err.println("Retrieval failed for source ='"
546                 + database.getSelectedItem() + "' and query\n'"
547                 + textArea.getText() + "'\n");
548         e.printStackTrace();
549       } catch (OutOfMemoryError e)
550       {
551         showErrorMessage("Out of Memory when retrieving "
552                 + textArea.getText() + " from " + database.getSelectedItem()
553                 + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n");
554         e.printStackTrace();
555       } catch (Error e)
556       {
557         showErrorMessage("Serious Error retrieving " + textArea.getText()
558                 + " from " + database.getSelectedItem());
559         e.printStackTrace();
560       }
561
562       // Stack results ready for opening in alignment windows
563       if (aresult != null && aresult.size() > 0)
564       {
565         FeatureSettingsModelI proxyColourScheme = proxy
566                 .getFeatureColourScheme();
567         if (proxyColourScheme != null)
568         {
569           preferredFeatureColours = proxyColourScheme;
570         }
571
572         AlignmentI ar = null;
573         if (proxy.isAlignmentSource())
574         {
575           addToLast = false;
576           // new window for each result
577           while (aresult.size() > 0)
578           {
579             presult.add(aresult.remove(0));
580             presultTitle.add(
581                     aresultq.remove(0) + " " + getDefaultRetrievalTitle());
582           }
583         }
584         else
585         {
586           String titl = null;
587           if (addToLast && presult.size() > 0)
588           {
589             ar = presult.remove(presult.size() - 1);
590             titl = presultTitle.remove(presultTitle.size() - 1);
591           }
592           // concatenate all results in one window
593           while (aresult.size() > 0)
594           {
595             if (ar == null)
596             {
597               ar = aresult.remove(0);
598             }
599             else
600             {
601               ar.append(aresult.remove(0));
602             }
603           }
604           addToLast = true;
605           presult.add(ar);
606           presultTitle.add(titl);
607         }
608       }
609       guiWindow.setProgressBar(
610               MessageManager.getString("status.finshed_querying"),
611               Thread.currentThread().hashCode());
612     }
613     guiWindow
614             .setProgressBar(
615                     (presult.size() > 0)
616                             ? MessageManager
617                                     .getString("status.parsing_results")
618                             : MessageManager.getString("status.processing"),
619                     Thread.currentThread().hashCode());
620     // process results
621     while (presult.size() > 0)
622     {
623       parseResult(presult.remove(0), presultTitle.remove(0), null,
624               preferredFeatureColours);
625     }
626     // only remove visual delay after we finished parsing.
627     guiWindow.setProgressBar(null, Thread.currentThread().hashCode());
628     if (nextFetch.size() > 0)
629     {
630       StringBuffer sb = new StringBuffer();
631       sb.append("Didn't retrieve the following "
632               + (nextFetch.size() == 1 ? "query"
633                       : nextFetch.size() + " queries")
634               + ": \n");
635       int l = sb.length(), lr = 0;
636       for (String s : nextFetch)
637       {
638         if (l != sb.length())
639         {
640           sb.append("; ");
641         }
642         if (lr - sb.length() > 40)
643         {
644           sb.append("\n");
645         }
646         sb.append(s);
647       }
648       showErrorMessage(sb.toString());
649     }
650     resetDialog();
651     if (closeDialog)
652     {
653       close_actionPerformed(null);
654     }
655   }
656
657   // ability to access the alignframe created/used in run+parseResult
658   private boolean saveAlignFrame = false;
659
660   private String savedAlignFrameId = null;
661
662   private Map savedAlignFrames = null;
663
664   public void saveAlignFrame(String id, Map map)
665   {
666     saveAlignFrame = true;
667     savedAlignFrameId = id;
668     savedAlignFrames = map;
669   }
670
671   public void resetSavedAlignFrames()
672   {
673     saveAlignFrame = false;
674     savedAlignFrameId = null;
675     savedAlignFrames = null;
676   }
677
678   /**
679    * Tries to fetch one or more accession ids from the database proxy
680    * 
681    * @param proxy
682    * @param accessions
683    *          the queries to fetch
684    * @param aresultq
685    *          a successful queries list to add to
686    * @param aresult
687    *          a list of retrieved alignments to add to
688    * @param nextFetch
689    *          failed queries are added to this list
690    * @throws Exception
691    */
692   void fetchMultipleAccessions(DbSourceProxy proxy,
693           Iterator<String> accessions, List<String> aresultq,
694           List<AlignmentI> aresult, List<String> nextFetch) throws Exception
695   {
696     StringBuilder multiacc = new StringBuilder();
697     List<String> tosend = new ArrayList<>();
698     while (accessions.hasNext())
699     {
700       String nel = accessions.next();
701       tosend.add(nel);
702       multiacc.append(nel);
703       if (accessions.hasNext())
704       {
705         multiacc.append(proxy.getAccessionSeparator());
706       }
707     }
708
709     try
710     {
711       String query = multiacc.toString();
712       AlignmentI rslt = proxy.getSequenceRecords(query);
713       if (rslt == null || rslt.getHeight() == 0)
714       {
715         // no results - pass on all queries to next source
716         nextFetch.addAll(tosend);
717       }
718       else
719       {
720         aresultq.add(query);
721         aresult.add(rslt);
722         if (tosend.size() > 1)
723         {
724           checkResultForQueries(rslt, tosend, nextFetch, proxy);
725         }
726       }
727     } catch (OutOfMemoryError oome)
728     {
729       new OOMWarning("fetching " + multiacc + " from "
730               + database.getSelectedItem(), oome, this);
731     }
732   }
733
734   /**
735    * Query for a single accession id via the database proxy
736    * 
737    * @param proxy
738    * @param accession
739    * @param aresultq
740    *          a list of successful queries to add to
741    * @param aresult
742    *          a list of retrieved alignments to add to
743    * @return true if the fetch was successful, else false
744    */
745   boolean fetchSingleAccession(DbSourceProxy proxy, String accession,
746           List<String> aresultq, List<AlignmentI> aresult)
747   {
748     boolean success = false;
749     try
750     {
751       if (aresult != null)
752       {
753         try
754         {
755           // give the server a chance to breathe
756           Thread.sleep(5);
757         } catch (Exception e)
758         {
759           //
760         }
761       }
762
763       AlignmentI indres = null;
764       try
765       {
766         indres = proxy.getSequenceRecords(accession);
767       } catch (OutOfMemoryError oome)
768       {
769         new OOMWarning(
770                 "fetching " + accession + " from " + proxy.getDbName(),
771                 oome, this);
772       }
773       if (indres != null)
774       {
775         aresultq.add(accession);
776         aresult.add(indres);
777         success = true;
778       }
779     } catch (Exception e)
780     {
781       Cache.log.info("Error retrieving " + accession + " from "
782               + proxy.getDbName(), e);
783     }
784     return success;
785   }
786
787   /**
788    * Checks which of the queries were successfully retrieved by searching the
789    * DBRefs of the retrieved sequences for a match. Any not found are added to
790    * the 'nextFetch' list.
791    * 
792    * @param rslt
793    * @param queries
794    * @param nextFetch
795    * @param proxy
796    */
797   void checkResultForQueries(AlignmentI rslt, List<String> queries,
798           List<String> nextFetch, DbSourceProxy proxy)
799   {
800     SequenceI[] rs = rslt.getSequencesArray();
801
802     for (String q : queries)
803     {
804       // BH 2019.01.25 dbr is never used.
805       // DBRefEntry dbr = new DBRefEntry();
806       // dbr.setSource(proxy.getDbSource());
807       // dbr.setVersion(null);
808       String accId = proxy.getAccessionIdFromQuery(q);
809       // dbr.setAccessionId(accId);
810       boolean rfound = false;
811       for (int r = 0, nr = rs.length; r < nr; r++)
812       {
813         if (rs[r] != null)
814         {
815           List<DBRefEntry> found = DBRefUtils.searchRefs(rs[r].getDBRefs(),
816                   accId);
817           if (!found.isEmpty())
818           {
819             rfound = true;
820             break;
821           }
822         }
823       }
824       if (!rfound)
825       {
826         nextFetch.add(q);
827       }
828     }
829   }
830
831   /**
832    * 
833    * @return a standard title for any results retrieved using the currently
834    *         selected source and settings
835    */
836   public String getDefaultRetrievalTitle()
837   {
838     return "Retrieved from " + database.getSelectedItem();
839   }
840
841   AlignmentI parseResult(AlignmentI al, String title,
842           FileFormatI currentFileFormat,
843           FeatureSettingsModelI preferredFeatureColours)
844   {
845
846     if (al != null && al.getHeight() > 0)
847     {
848       if (title == null)
849       {
850         title = getDefaultRetrievalTitle();
851       }
852       if (alignFrame == null)
853       {
854         AlignFrame af = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
855                 AlignFrame.DEFAULT_HEIGHT);
856         if (saveAlignFrame && savedAlignFrames != null)
857         {
858           savedAlignFrames.put(savedAlignFrameId, af);
859         }
860         if (currentFileFormat != null)
861         {
862           af.currentFileFormat = currentFileFormat;
863         }
864
865         List<SequenceI> alsqs = al.getSequences();
866         synchronized (alsqs)
867         {
868           for (SequenceI sq : alsqs)
869           {
870             if (sq.getFeatures().hasFeatures())
871             {
872               af.setShowSeqFeatures(true);
873               break;
874             }
875           }
876         }
877
878         if (preferredFeatureColours != null)
879         {
880           af.getViewport().applyFeaturesStyle(preferredFeatureColours);
881         }
882         if (Cache.getDefault("HIDE_INTRONS", true))
883         {
884           af.hideFeatureColumns(SequenceOntologyI.EXON, false);
885         }
886         Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH,
887                 AlignFrame.DEFAULT_HEIGHT);
888
889         af.setStatus(MessageManager
890                 .getString("label.successfully_pasted_alignment_file"));
891
892         try
893         {
894           af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false));
895         } catch (Exception ex)
896         {
897         }
898       }
899       else
900       {
901         if (saveAlignFrame && savedAlignFrames != null)
902         {
903           savedAlignFrames.put(savedAlignFrameId, alignFrame);
904         }
905         alignFrame.viewport.addAlignment(al, title);
906       }
907     }
908     return al;
909   }
910
911   void showErrorMessage(final String error)
912   {
913     resetDialog();
914     javax.swing.SwingUtilities.invokeLater(new Runnable()
915     {
916       @Override
917       public void run()
918       {
919         JvOptionPane.showInternalMessageDialog(Desktop.desktop, error,
920                 MessageManager.getString("label.error_retrieving_data"),
921                 JvOptionPane.WARNING_MESSAGE);
922       }
923     });
924   }
925
926   public IProgressIndicator getProgressIndicator()
927   {
928     return progressIndicator;
929   }
930
931   public void setProgressIndicator(IProgressIndicator progressIndicator)
932   {
933     this.progressIndicator = progressIndicator;
934   }
935
936   /**
937    * Hide this panel (on clicking the database button to open the database
938    * chooser)
939    */
940   void hidePanel()
941   {
942     frame.setVisible(false);
943   }
944
945   public void setQuery(String ids)
946   {
947     textArea.setText(ids);
948   }
949
950   /**
951    * Called to modify the search panel for embedding as an alternative tab of a
952    * free text search panel. The database choice list is hidden (since the
953    * choice has been made), and a Back button is made visible (which reopens the
954    * Sequence Fetcher panel).
955    * 
956    * @param parentPanel
957    */
958   public void embedIn(GFTSPanel parentPanel)
959   {
960     database.setVisible(false);
961     backBtn.setVisible(true);
962     parentSearchPanel = parentPanel;
963   }
964 }