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