X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSequenceFetcher.java;h=f9d7760fcfb37863cc980e8c53ec51a341ac2bbb;hb=0d3ab54f8c983e5c0b5ce0d354024268d323b6af;hp=7ffd3e4025f9c4b21fc9b34beb31d2fd58154be3;hpb=81310fc2ebbe043b33ca5c6cfb7154d22c2599b1;p=jalview.git diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index 7ffd3e4..f9d7760 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -1,397 +1,442 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7) - * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; -import java.util.*; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; - -import jalview.datamodel.*; -import jalview.io.*; -import jalview.ws.dbsources.das.api.DasSourceRegistryI; +import jalview.api.FeatureSettingsModelI; +import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.SequenceI; +import jalview.fts.core.GFTSPanel; +import jalview.fts.service.pdb.PDBFTSPanel; +import jalview.fts.service.uniprot.UniprotFTSPanel; +import jalview.io.FileFormatI; +import jalview.io.gff.SequenceOntologyI; +import jalview.util.DBRefUtils; +import jalview.util.MessageManager; +import jalview.util.Platform; import jalview.ws.seqfetcher.DbSourceProxy; import java.awt.BorderLayout; - +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingConstants; + +/** + * A panel where the use may choose a database source, and enter one or more + * accessions, to retrieve entries from the database. + *

+ * If the selected source is Uniprot or PDB, a free text search panel is opened + * instead to perform the search and selection. + */ public class SequenceFetcher extends JPanel implements Runnable { - // ASequenceFetcher sfetch; - JInternalFrame frame; + private static jalview.ws.SequenceFetcher sfetch = null; - IProgressIndicator guiWindow; + JLabel exampleAccession; - AlignFrame alignFrame; + JComboBox database; - StringBuffer result; + JCheckBox replacePunctuation; - final String noDbSelected = "-- Select Database --"; + JButton okBtn; - Hashtable sources = new Hashtable(); + JButton exampleBtn; - private static jalview.ws.SequenceFetcher sfetch = null; + JButton closeBtn; - private static DasSourceRegistryI dasRegistry = null; + JButton backBtn; - private static boolean _initingFetcher = false; + JTextArea textArea; - private static Thread initingThread = null; + JInternalFrame frame; + + IProgressIndicator guiWindow; + + AlignFrame alignFrame; + + GFTSPanel parentSearchPanel; + + IProgressIndicator progressIndicator; + + volatile boolean _isConstructing = false; /** - * Blocking method that initialises and returns the shared instance of the - * SequenceFetcher client + * Returns the shared instance of the SequenceFetcher client * - * @param guiWindow - * - where the initialisation delay message should be shown - * @return the singleton instance of the sequence fetcher client + * @return */ - public static jalview.ws.SequenceFetcher getSequenceFetcherSingleton( - final IProgressIndicator guiWindow) + public static jalview.ws.SequenceFetcher getSequenceFetcherSingleton() { - if (_initingFetcher && initingThread != null && initingThread.isAlive()) - { - if (guiWindow != null) - { - guiWindow.setProgressBar( - "Waiting for Sequence Database Fetchers to initialise", - Thread.currentThread().hashCode()); - } - // initting happening on another thread - so wait around to see if it - // finishes. - while (_initingFetcher && initingThread != null - && initingThread.isAlive()) - { - try - { - Thread.sleep(10); - } catch (Exception e) - { - } - ; - } - if (guiWindow != null) - { - guiWindow.setProgressBar( - "Waiting for Sequence Database Fetchers to initialise", - Thread.currentThread().hashCode()); - } - } - if (sfetch == null - || dasRegistry != jalview.bin.Cache.getDasSourceRegistry()) + if (sfetch == null) { - _initingFetcher = true; - initingThread = Thread.currentThread(); - /** - * give a visual indication that sequence fetcher construction is occuring - */ - if (guiWindow != null) - { - guiWindow.setProgressBar("Initialising Sequence Database Fetchers", - Thread.currentThread().hashCode()); - } - dasRegistry = jalview.bin.Cache.getDasSourceRegistry(); - dasRegistry.refreshSources(); - - jalview.ws.SequenceFetcher sf = new jalview.ws.SequenceFetcher(); - if (guiWindow != null) - { - guiWindow.setProgressBar("Initialising Sequence Database Fetchers", - Thread.currentThread().hashCode()); - } - sfetch = sf; - _initingFetcher = false; - initingThread = null; + sfetch = new jalview.ws.SequenceFetcher(); } return sfetch; } + /** + * Constructor given a client to receive any status or progress messages + * (currently either the Desktop, or an AlignFrame panel) + * + * @param guiIndic + */ public SequenceFetcher(IProgressIndicator guiIndic) { - final IProgressIndicator guiWindow = guiIndic; - final SequenceFetcher us = this; - // launch initialiser thread - Thread sf = new Thread(new Runnable() - { - - public void run() - { - if (getSequenceFetcherSingleton(guiWindow) != null) - { - us.initGui(guiWindow); - } - else - { - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - public void run() - { - JOptionPane - .showInternalMessageDialog( - Desktop.desktop, - "Could not create the sequence fetcher client. Check error logs for details.", - "Couldn't create SequenceFetcher", - JOptionPane.ERROR_MESSAGE); - } - }); - - // raise warning dialog - } - } - }); - sf.start(); + this(guiIndic, null, null); } /** - * called by thread spawned by constructor + * Constructor with specified database and accession(s) to retrieve * - * @param guiWindow + * @param guiIndic + * @param selectedDb + * @param queryString */ - private void initGui(IProgressIndicator guiWindow) + public SequenceFetcher(IProgressIndicator guiIndic, + final String selectedDb, final String queryString) { - this.guiWindow = guiWindow; - if (guiWindow instanceof AlignFrame) - { - alignFrame = (AlignFrame) guiWindow; - } + this.progressIndicator = guiIndic; + getSequenceFetcherSingleton(); + this.guiWindow = progressIndicator; - database.addItem(noDbSelected); - /* - * Dynamically generated database list will need a translation function from - * internal source to externally distinct names. UNIPROT and UP_NAME are - * identical DB sources, and should be collapsed. - */ - - String dbs[] = sfetch.getOrderedSupportedSources(); - for (int i = 0; i < dbs.length; i++) + if (progressIndicator instanceof AlignFrame) { - if (!sources.containsValue(dbs[i])) - { - String name = sfetch.getSourceProxy(dbs[i]).getDbName(); - // duplicate source names are thrown away, here. - if (!sources.containsKey(name)) - { - database.addItem(name); - } - // overwrite with latest version of the retriever for this source - sources.put(name, dbs[i]); - } - } - try - { - jbInit(); - } catch (Exception ex) - { - ex.printStackTrace(); + alignFrame = (AlignFrame) progressIndicator; } + jbInit(selectedDb); + textArea.setText(queryString); + frame = new JInternalFrame(); frame.setContentPane(this); - if (new jalview.util.Platform().isAMac()) - { - Desktop.addInternalFrame(frame, getFrameTitle(), 400, 240); - } - else - { - Desktop.addInternalFrame(frame, getFrameTitle(), 400, 180); - } + int height = Platform.isAMac() ? 240 : 180; + Desktop.addInternalFrame(frame, getFrameTitle(), true, 400, height); } private String getFrameTitle() { - return ((alignFrame == null) ? "New " : "Additional ") - + "Sequence Fetcher"; + return ((alignFrame == null) + ? MessageManager.getString("label.new_sequence_fetcher") + : MessageManager + .getString("label.additional_sequence_fetcher")); } - private void jbInit() throws Exception + private void jbInit(String selectedDb) { - this.setLayout(borderLayout2); + this.setLayout(new BorderLayout()); + database = new JComboBox<>(); database.setFont(JvSwingUtils.getLabelFont()); - dbeg.setFont(new java.awt.Font("Verdana", Font.BOLD, 11)); - jLabel1.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11)); + database.setPrototypeDisplayValue("ENSEMBLGENOMES "); + String[] sources = new jalview.ws.SequenceFetcher().getSupportedDb(); + Arrays.sort(sources, String.CASE_INSENSITIVE_ORDER); + database.addItem(MessageManager.getString("action.select_ddbb")); + for (String source : sources) + { + database.addItem(source); + } + database.setSelectedItem(selectedDb); + if (database.getSelectedIndex() == -1) + { + database.setSelectedIndex(0); + } + database.setMaximumRowCount(database.getItemCount()); + database.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + String currentSelection = (String) database.getSelectedItem(); + updateExampleQuery(currentSelection); + + if ("pdb".equalsIgnoreCase(currentSelection)) + { + new PDBFTSPanel(SequenceFetcher.this); + frame.dispose(); + } + else if ("uniprot".equalsIgnoreCase(currentSelection)) + { + new UniprotFTSPanel(SequenceFetcher.this); + frame.dispose(); + } + else + { + otherSourceAction(); + } + } + }); + + exampleAccession = new JLabel(""); + exampleAccession.setFont(new Font("Verdana", Font.BOLD, 11)); + JLabel jLabel1 = new JLabel(MessageManager + .getString("label.separate_multiple_accession_ids")); + jLabel1.setFont(new Font("Verdana", Font.ITALIC, 11)); jLabel1.setHorizontalAlignment(SwingConstants.CENTER); - jLabel1.setText("Separate multiple accession ids with semi colon \";\""); + replacePunctuation = new JCheckBox( + MessageManager.getString("label.replace_commas_semicolons")); replacePunctuation.setHorizontalAlignment(SwingConstants.CENTER); - replacePunctuation - .setFont(new java.awt.Font("Verdana", Font.ITALIC, 11)); - replacePunctuation.setText("Replace commas with semi-colons"); - ok.setText("OK"); - ok.addActionListener(new ActionListener() + replacePunctuation.setFont(new Font("Verdana", Font.ITALIC, 11)); + okBtn = new JButton(MessageManager.getString("action.ok")); + okBtn.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { ok_actionPerformed(); } }); - clear.setText("Clear"); + JButton clear = new JButton(MessageManager.getString("action.clear")); clear.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { clear_actionPerformed(); } }); - example.setText("Example"); - example.addActionListener(new ActionListener() + exampleBtn = new JButton(MessageManager.getString("label.example")); + exampleBtn.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { example_actionPerformed(); } }); - close.setText("Close"); - close.addActionListener(new ActionListener() + closeBtn = new JButton(MessageManager.getString("action.cancel")); + closeBtn.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { close_actionPerformed(e); } }); + backBtn = new JButton(MessageManager.getString("action.back")); + backBtn.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + parentSearchPanel.btn_back_ActionPerformed(); + } + }); + // back not visible unless embedded + backBtn.setVisible(false); + + textArea = new JTextArea(); textArea.setFont(JvSwingUtils.getLabelFont()); textArea.setLineWrap(true); textArea.addKeyListener(new KeyAdapter() { + @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) + { ok_actionPerformed(); + } } }); - jPanel3.setLayout(borderLayout1); - borderLayout1.setVgap(5); - jPanel1.add(ok); - jPanel1.add(example); - jPanel1.add(clear); - jPanel1.add(close); - jPanel3.add(jPanel2, java.awt.BorderLayout.CENTER); - jPanel2.setLayout(borderLayout3); - database.addActionListener(new ActionListener() - { + JPanel actionPanel = new JPanel(); + actionPanel.add(backBtn); + actionPanel.add(exampleBtn); + actionPanel.add(clear); + actionPanel.add(okBtn); + actionPanel.add(closeBtn); + + JPanel databasePanel = new JPanel(); + databasePanel.setLayout(new BorderLayout()); + databasePanel.add(database, BorderLayout.NORTH); + databasePanel.add(exampleAccession, BorderLayout.CENTER); + JPanel jPanel2a = new JPanel(new BorderLayout()); + jPanel2a.add(jLabel1, BorderLayout.NORTH); + jPanel2a.add(replacePunctuation, BorderLayout.SOUTH); + databasePanel.add(jPanel2a, BorderLayout.SOUTH); - public void actionPerformed(ActionEvent e) + JPanel idsPanel = new JPanel(); + idsPanel.setLayout(new BorderLayout(0, 5)); + JScrollPane jScrollPane1 = new JScrollPane(); + jScrollPane1.getViewport().add(textArea); + idsPanel.add(jScrollPane1, BorderLayout.CENTER); + + this.add(actionPanel, BorderLayout.SOUTH); + this.add(idsPanel, BorderLayout.CENTER); + this.add(databasePanel, BorderLayout.NORTH); + } + + /** + * Answers a semi-colon-delimited string with the example query or queries for + * the selected database + * + * @param db + * @return + */ + protected String getExampleQueries(String db) + { + StringBuilder sb = new StringBuilder(); + HashSet hs = new HashSet<>(); + for (DbSourceProxy dbs : sfetch.getSourceProxy(db)) + { + String tq = dbs.getTestQuery(); + if (hs.add(tq)) // not a duplicate source { - DbSourceProxy db = null; - try - { - db = sfetch.getSourceProxy((String) sources.get(database - .getSelectedItem())); - String eq = db.getTestQuery(); - dbeg.setText("Example query: " + eq); - replacePunctuation.setEnabled(!(eq != null && eq.indexOf(",") > -1)); - } catch (Exception ex) + if (sb.length() > 0) { - dbeg.setText(""); - replacePunctuation.setEnabled(true); + sb.append(";"); } - jPanel2.repaint(); + sb.append(tq); } - }); - dbeg.setText(""); - jPanel2.add(database, java.awt.BorderLayout.NORTH); - jPanel2.add(dbeg, java.awt.BorderLayout.CENTER); - JPanel jPanel2a = new JPanel(new BorderLayout()); - jPanel2a.add(jLabel1, java.awt.BorderLayout.NORTH); - jPanel2a.add(replacePunctuation, java.awt.BorderLayout.SOUTH); - jPanel2.add(jPanel2a, java.awt.BorderLayout.SOUTH); - // jPanel2.setPreferredSize(new Dimension()) - jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER); - this.add(jPanel1, java.awt.BorderLayout.SOUTH); - this.add(jPanel3, java.awt.BorderLayout.CENTER); - this.add(jPanel2, java.awt.BorderLayout.NORTH); - jScrollPane1.getViewport().add(textArea); - + } + return sb.toString(); } - protected void example_actionPerformed() + /** + * Action on selecting a database other than Uniprot or PDB is to enable or + * disable 'Replace commas', and await input in the query field + */ + protected void otherSourceAction() { - DbSourceProxy db = null; try { - db = sfetch.getSourceProxy((String) sources.get(database - .getSelectedItem())); - textArea.setText(db.getTestQuery()); + String eq = exampleAccession.getText(); + // TODO this should be a property of the SequenceFetcher whether commas + // are allowed in the IDs... + + boolean enablePunct = !(eq != null && eq.indexOf(",") > -1); + replacePunctuation.setEnabled(enablePunct); + } catch (Exception ex) { + exampleAccession.setText(""); + replacePunctuation.setEnabled(true); } - jPanel3.repaint(); + repaint(); } - protected void clear_actionPerformed() + /** + * Sets the text of the example query to incorporate the example accession + * provided by the selected database source + * + * @param selectedDatabase + * @return + */ + protected String updateExampleQuery(String selectedDatabase) { - textArea.setText(""); - jPanel3.repaint(); + String eq = getExampleQueries(selectedDatabase); + exampleAccession.setText(MessageManager + .formatMessage("label.example_query_param", new String[] + { eq })); + return eq; } - JLabel dbeg = new JLabel(); - - JComboBox database = new JComboBox(); - - JLabel jLabel1 = new JLabel(); - - JCheckBox replacePunctuation = new JCheckBox(); - - JButton ok = new JButton(); - - JButton clear = new JButton(); - - JButton example = new JButton(); - - JButton close = new JButton(); - - JPanel jPanel1 = new JPanel(); - - JTextArea textArea = new JTextArea(); - - JScrollPane jScrollPane1 = new JScrollPane(); - - JPanel jPanel2 = new JPanel(); - - JPanel jPanel3 = new JPanel(); - - JPanel jPanel4 = new JPanel(); - - BorderLayout borderLayout1 = new BorderLayout(); - - BorderLayout borderLayout2 = new BorderLayout(); + /** + * Action on clicking the 'Example' button is to write the example accession + * as the query text field value + */ + protected void example_actionPerformed() + { + String eq = getExampleQueries((String) database.getSelectedItem()); + textArea.setText(eq); + repaint(); + } - BorderLayout borderLayout3 = new BorderLayout(); + /** + * Clears the query input field + */ + protected void clear_actionPerformed() + { + textArea.setText(""); + repaint(); + } - public void close_actionPerformed(ActionEvent e) + /** + * Action on Close button is to close this frame, and also (if it is embedded + * in a search panel) to close the search panel + * + * @param e + */ + protected void close_actionPerformed(ActionEvent e) { try { frame.setClosed(true); + if (parentSearchPanel != null) + { + parentSearchPanel.btn_cancel_ActionPerformed(); + } } catch (Exception ex) { } } + /** + * Action on OK is to start the fetch for entered accession(s) + */ public void ok_actionPerformed() { - database.setEnabled(false); + /* + * tidy inputs and check there is something to search for + */ + String text = textArea.getText(); + if (replacePunctuation.isEnabled() && replacePunctuation.isSelected()) + { + text = text.replace(",", ";"); + } + text = text.replaceAll("(\\s|[,; ])+", ";"); + textArea.setText(text); + if (text.isEmpty()) + { + // todo i18n + showErrorMessage( + "Please enter a (semi-colon separated list of) database id(s)"); + resetDialog(); + return; + } + exampleBtn.setEnabled(false); textArea.setEnabled(false); - ok.setEnabled(false); - close.setEnabled(false); + okBtn.setEnabled(false); + closeBtn.setEnabled(false); + backBtn.setEnabled(false); Thread worker = new Thread(this); worker.start(); @@ -399,415 +444,405 @@ public class SequenceFetcher extends JPanel implements Runnable private void resetDialog() { - database.setEnabled(true); + exampleBtn.setEnabled(true); textArea.setEnabled(true); - ok.setEnabled(true); - close.setEnabled(true); + okBtn.setEnabled(true); + closeBtn.setEnabled(true); + backBtn.setEnabled(parentSearchPanel != null); } + @Override public void run() { - String error = ""; - if (database.getSelectedItem().equals(noDbSelected)) - { - error += "Please select the source database\n"; - } - // TODO: make this transformation more configurable - com.stevesoft.pat.Regex empty; - if (replacePunctuation.isEnabled() && replacePunctuation.isSelected()) - { - empty = new com.stevesoft.pat.Regex( - // replace commas and spaces with a semicolon - "(\\s|[,; ])+", ";"); - } - else - { - // just turn spaces and semicolons into single semicolons - empty = new com.stevesoft.pat.Regex("(\\s|[; ])+", ";"); - } - textArea.setText(empty.replaceAll(textArea.getText())); - // see if there's anthing to search with - if (!new com.stevesoft.pat.Regex("[A-Za-z0-9_.]").search(textArea - .getText())) - { - error += "Please enter a (semi-colon separated list of) database id(s)"; - } - if (error.length() > 0) - { - showErrorMessage(error); - resetDialog(); - return; - } - ArrayList aresultq=new ArrayList(); - ArrayList aresult = new ArrayList(); - Object source = database.getSelectedItem(); - Enumeration en = new StringTokenizer(textArea.getText(), ";"); - boolean isAliSource=false; - try - { - guiWindow.setProgressBar( - "Fetching Sequences from " + database.getSelectedItem(), - Thread.currentThread().hashCode()); - DbSourceProxy proxy = sfetch.getSourceProxy((String) sources - .get(source)); - isAliSource = proxy.isA(DBRefSource.ALIGNMENTDB); - if (proxy.getAccessionSeparator() == null) + boolean addToLast = false; + List aresultq = new ArrayList<>(); + List presultTitle = new ArrayList<>(); + List presult = new ArrayList<>(); + List aresult = new ArrayList<>(); + List sources = sfetch + .getSourceProxy((String) database.getSelectedItem()); + Iterator proxies = sources.iterator(); + String[] qries; + List nextFetch = Arrays + .asList(qries = textArea.getText().split(";")); + Iterator en = Arrays.asList(new String[0]).iterator(); + int nqueries = qries.length; + + FeatureSettingsModelI preferredFeatureColours = null; + while (proxies.hasNext() && (en.hasNext() || nextFetch.size() > 0)) + { + if (!en.hasNext() && nextFetch.size() > 0) + { + en = nextFetch.iterator(); + nqueries = nextFetch.size(); + // save the remaining queries in the original array + qries = nextFetch.toArray(new String[nqueries]); + nextFetch = new ArrayList<>(); + } + + DbSourceProxy proxy = proxies.next(); + try { - while (en.hasMoreElements()) + // update status + guiWindow.setProgressBar(MessageManager.formatMessage( + "status.fetching_sequence_queries_from", new String[] + { Integer.valueOf(nqueries).toString(), + proxy.getDbName() }), + Thread.currentThread().hashCode()); + if (proxy.getMaximumQueryCount() == 1) { - String item = (String) en.nextElement(); - try + /* + * proxy only handles one accession id at a time + */ + while (en.hasNext()) { - if (aresult != null) + String acc = en.next(); + if (!fetchSingleAccession(proxy, acc, aresultq, aresult)) { - try - { - // give the server a chance to breathe - Thread.sleep(5); - } catch (Exception e) - { - // - } - + nextFetch.add(acc); } + } + } + else + { + /* + * proxy can fetch multiple accessions at one time + */ + fetchMultipleAccessions(proxy, en, aresultq, aresult, nextFetch); + } + } catch (Exception e) + { + showErrorMessage("Error retrieving " + textArea.getText() + " from " + + database.getSelectedItem()); + // error + // +="Couldn't retrieve sequences from "+database.getSelectedItem(); + System.err.println("Retrieval failed for source ='" + + database.getSelectedItem() + "' and query\n'" + + textArea.getText() + "'\n"); + e.printStackTrace(); + } catch (OutOfMemoryError e) + { + showErrorMessage("Out of Memory when retrieving " + + textArea.getText() + " from " + database.getSelectedItem() + + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n"); + e.printStackTrace(); + } catch (Error e) + { + showErrorMessage("Serious Error retrieving " + textArea.getText() + + " from " + database.getSelectedItem()); + e.printStackTrace(); + } - AlignmentI indres = null; - try - { - indres = proxy.getSequenceRecords(item); - } catch (OutOfMemoryError oome) + // Stack results ready for opening in alignment windows + if (aresult != null && aresult.size() > 0) + { + FeatureSettingsModelI proxyColourScheme = proxy + .getFeatureColourScheme(); + if (proxyColourScheme != null) + { + preferredFeatureColours = proxyColourScheme; + } + + AlignmentI ar = null; + if (proxy.isAlignmentSource()) + { + addToLast = false; + // new window for each result + while (aresult.size() > 0) + { + presult.add(aresult.remove(0)); + presultTitle.add( + aresultq.remove(0) + " " + getDefaultRetrievalTitle()); + } + } + else + { + String titl = null; + if (addToLast && presult.size() > 0) + { + ar = presult.remove(presult.size() - 1); + titl = presultTitle.remove(presultTitle.size() - 1); + } + // concatenate all results in one window + while (aresult.size() > 0) + { + if (ar == null) { - new OOMWarning("fetching " + item + " from " - + database.getSelectedItem(), oome, this); + ar = aresult.remove(0); } - if (indres != null) + else { - aresultq.add(item); - aresult.add(indres); + ar.append(aresult.remove(0)); } - } catch (Exception e) - { - jalview.bin.Cache.log.info("Error retrieving " + item - + " from " + source, e); } + addToLast = true; + presult.add(ar); + presultTitle.add(titl); } } - else + guiWindow.setProgressBar( + MessageManager.getString("status.finshed_querying"), + Thread.currentThread().hashCode()); + } + guiWindow + .setProgressBar( + (presult.size() > 0) + ? MessageManager + .getString("status.parsing_results") + : MessageManager.getString("status.processing"), + Thread.currentThread().hashCode()); + // process results + while (presult.size() > 0) + { + parseResult(presult.remove(0), presultTitle.remove(0), null, + preferredFeatureColours); + } + // only remove visual delay after we finished parsing. + guiWindow.setProgressBar(null, Thread.currentThread().hashCode()); + if (nextFetch.size() > 0) + { + StringBuffer sb = new StringBuffer(); + sb.append("Didn't retrieve the following " + + (nextFetch.size() == 1 ? "query" + : nextFetch.size() + " queries") + + ": \n"); + int l = sb.length(), lr = 0; + for (String s : nextFetch) { - StringBuffer multiacc = new StringBuffer(); - while (en.hasMoreElements()) + if (l != sb.length()) { - multiacc.append(en.nextElement()); - if (en.hasMoreElements()) - { - multiacc.append(proxy.getAccessionSeparator()); - } + sb.append("; "); } - try + if (lr - sb.length() > 40) { - aresultq.add(multiacc.toString()); - aresult.add(proxy.getSequenceRecords(multiacc.toString())); - } catch (OutOfMemoryError oome) - { - new OOMWarning("fetching " + multiacc + " from " - + database.getSelectedItem(), oome, this); + sb.append("\n"); } - + sb.append(s); } + showErrorMessage(sb.toString()); + } + resetDialog(); + } - } catch (Exception e) - { - showErrorMessage("Error retrieving " + textArea.getText() + " from " - + database.getSelectedItem()); - // error +="Couldn't retrieve sequences from "+database.getSelectedItem(); - System.err.println("Retrieval failed for source ='" - + database.getSelectedItem() + "' and query\n'" - + textArea.getText() + "'\n"); - e.printStackTrace(); - } catch (OutOfMemoryError e) - { - // resets dialog box - so we don't use OOMwarning here. - showErrorMessage("Out of Memory when retrieving " - + textArea.getText() - + " from " - + database.getSelectedItem() - + "\nPlease see the Jalview FAQ for instructions for increasing the memory available to Jalview.\n"); - e.printStackTrace(); - } catch (Error e) - { - showErrorMessage("Serious Error retrieving " + textArea.getText() - + " from " + database.getSelectedItem()); - e.printStackTrace(); + /** + * Tries to fetch one or more accession ids from the database proxy + * + * @param proxy + * @param accessions + * the queries to fetch + * @param aresultq + * a successful queries list to add to + * @param aresult + * a list of retrieved alignments to add to + * @param nextFetch + * failed queries are added to this list + * @throws Exception + */ + void fetchMultipleAccessions(DbSourceProxy proxy, + Iterator accessions, List aresultq, + List aresult, List nextFetch) throws Exception + { + StringBuilder multiacc = new StringBuilder(); + List tosend = new ArrayList<>(); + while (accessions.hasNext()) + { + String nel = accessions.next(); + tosend.add(nel); + multiacc.append(nel); + if (accessions.hasNext()) + { + multiacc.append(proxy.getAccessionSeparator()); + } } - if (aresult != null && aresult.size()>0) + + try { - AlignmentI ar=null; - if (isAliSource) { - // new window for each result - while (aresult.size()>0) - { - parseResult(aresult.remove(0), aresultq.remove(0)+" "+getDefaultRetrievalTitle(), null); - } - } else { - // concatenate all results in one window - while (aresult.size()>0) + String query = multiacc.toString(); + AlignmentI rslt = proxy.getSequenceRecords(query); + if (rslt == null || rslt.getHeight() == 0) + { + // no results - pass on all queries to next source + nextFetch.addAll(tosend); + } + else + { + aresultq.add(query); + aresult.add(rslt); + if (tosend.size() > 1) { - if (ar==null) { ar = aresult.remove(0);} - else { ar.append(aresult.remove(0)); }; + checkResultForQueries(rslt, tosend, nextFetch, proxy); } - parseResult(ar, null, null); - } + } + } catch (OutOfMemoryError oome) + { + new OOMWarning("fetching " + multiacc + " from " + + database.getSelectedItem(), oome, this); } - // only remove visual delay after we finished parsing. - guiWindow.setProgressBar(null, Thread.currentThread().hashCode()); - resetDialog(); } - /* - * result = new StringBuffer(); if - * (database.getSelectedItem().equals("Uniprot")) { - * getUniprotFile(textArea.getText()); } else if - * (database.getSelectedItem().equals("EMBL") || - * database.getSelectedItem().equals("EMBLCDS")) { String DBRefSource = - * database.getSelectedItem().equals("EMBLCDS") ? - * jalview.datamodel.DBRefSource.EMBLCDS : jalview.datamodel.DBRefSource.EMBL; - * - * StringTokenizer st = new StringTokenizer(textArea.getText(), ";"); - * SequenceI[] seqs = null; while(st.hasMoreTokens()) { EBIFetchClient dbFetch - * = new EBIFetchClient(); String qry = - * database.getSelectedItem().toString().toLowerCase( ) + ":" + - * st.nextToken(); File reply = dbFetch.fetchDataAsFile( qry, "emblxml",null); - * - * jalview.datamodel.xdb.embl.EmblFile efile=null; if (reply != null && - * reply.exists()) { efile = - * jalview.datamodel.xdb.embl.EmblFile.getEmblFile(reply); } if (efile!=null) - * { for (Iterator i=efile.getEntries().iterator(); i.hasNext(); ) { EmblEntry - * entry = (EmblEntry) i.next(); SequenceI[] seqparts = - * entry.getSequences(false,true, DBRefSource); if (seqparts!=null) { - * SequenceI[] newseqs = null; int si=0; if (seqs==null) { newseqs = new - * SequenceI[seqparts.length]; } else { newseqs = new - * SequenceI[seqs.length+seqparts.length]; - * - * for (;si0) { if (parseResult(new Alignment(seqs), null, - * null)!=null) { result.append("# Successfully parsed the - * "+database.getSelectedItem()+" Queries into an Alignment"); } } } else if - * (database.getSelectedItem().equals("PDB")) { StringTokenizer qset = new - * StringTokenizer(textArea.getText(), ";"); String query; SequenceI[] seqs = - * null; while (qset.hasMoreTokens() && ((query = qset.nextToken())!=null)) { - * SequenceI[] seqparts = getPDBFile(query.toUpperCase()); if (seqparts != - * null) { if (seqs == null) { seqs = seqparts; } else { SequenceI[] newseqs = - * new SequenceI[seqs.length+seqparts.length]; int i=0; for (; i < - * seqs.length; i++) { newseqs[i] = seqs[i]; seqs[i] = null; } for (int - * j=0;j 0) { if (parseResult(new - * Alignment(seqs), null, null)!=null) { result.append( "# Successfully parsed - * the PDB File Queries into an - * Alignment"); } } } else if( database.getSelectedItem().equals("PFAM")) { - * try { result.append(new FastaFile( - * "http://www.sanger.ac.uk/cgi-bin/Pfam/getalignment.pl?format=fal&acc=" + - * textArea.getText().toUpperCase(), "URL").print() ); - * - * if(result.length()>0) { parseResult( result.toString(), - * textArea.getText().toUpperCase() ); } } catch (java.io.IOException ex) { - * result = null; } } - * - * if (result == null || result.length() == 0) { showErrorMessage("Error - * retrieving " + textArea.getText() + " from " + database.getSelectedItem()); - * } - * - * resetDialog(); return; } - * - * void getUniprotFile(String id) { EBIFetchClient ebi = new EBIFetchClient(); - * File file = ebi.fetchDataAsFile("uniprot:" + id, "xml", null); - * - * DBRefFetcher dbref = new DBRefFetcher(); Vector entries = - * dbref.getUniprotEntries(file); - * - * if (entries != null) { //First, make the new sequences Enumeration en = - * entries.elements(); while (en.hasMoreElements()) { UniprotEntry entry = - * (UniprotEntry) en.nextElement(); - * - * StringBuffer name = new StringBuffer(">UniProt/Swiss-Prot"); Enumeration - * en2 = entry.getAccession().elements(); while (en2.hasMoreElements()) { - * name.append("|"); name.append(en2.nextElement()); } en2 = - * entry.getName().elements(); while (en2.hasMoreElements()) { - * name.append("|"); name.append(en2.nextElement()); } - * - * if (entry.getProtein() != null) { name.append(" " + - * entry.getProtein().getName().elementAt(0)); } - * - * result.append(name + "\n" + entry.getUniprotSequence().getContent() + - * "\n"); } - * - * //Then read in the features and apply them to the dataset Alignment al = - * parseResult(result.toString(), null); for (int i = 0; i < entries.size(); - * i++) { UniprotEntry entry = (UniprotEntry) entries.elementAt(i); - * Enumeration e = entry.getDbReference().elements(); Vector onlyPdbEntries = - * new Vector(); while (e.hasMoreElements()) { PDBEntry pdb = (PDBEntry) - * e.nextElement(); if (!pdb.getType().equals("PDB")) { continue; } - * - * onlyPdbEntries.addElement(pdb); } - * - * Enumeration en2 = entry.getAccession().elements(); while - * (en2.hasMoreElements()) { - * al.getSequenceAt(i).getDatasetSequence().addDBRef(new DBRefEntry( - * DBRefSource.UNIPROT, "0", en2.nextElement().toString())); } - * - * - * - * - * al.getSequenceAt(i).getDatasetSequence().setPDBId(onlyPdbEntries); if - * (entry.getFeature() != null) { e = entry.getFeature().elements(); while - * (e.hasMoreElements()) { SequenceFeature sf = (SequenceFeature) - * e.nextElement(); sf.setFeatureGroup("Uniprot"); - * al.getSequenceAt(i).getDatasetSequence().addSequenceFeature( sf ); } } } } - * } - * - * SequenceI[] getPDBFile(String id) { Vector result = new Vector(); String - * chain = null; if (id.indexOf(":") > -1) { chain = - * id.substring(id.indexOf(":") + 1); id = id.substring(0, id.indexOf(":")); } - * - * EBIFetchClient ebi = new EBIFetchClient(); String file = - * ebi.fetchDataAsFile("pdb:" + id, "pdb", "raw"). getAbsolutePath(); if (file - * == null) { return null; } try { PDBfile pdbfile = new PDBfile(file, - * jalview.io.AppletFormatAdapter.FILE); for (int i = 0; i < - * pdbfile.chains.size(); i++) { if (chain == null || ( (PDBChain) - * pdbfile.chains.elementAt(i)).id. toUpperCase().equals(chain)) { PDBChain - * pdbchain = (PDBChain) pdbfile.chains.elementAt(i); // Get the Chain's - * Sequence - who's dataset includes any special features added from the PDB - * file SequenceI sq = pdbchain.sequence; // Specially formatted name for the - * PDB chain sequences retrieved from the PDB - * sq.setName("PDB|"+id+"|"+sq.getName()); // Might need to add more metadata - * to the PDBEntry object // like below /* PDBEntry entry = new PDBEntry(); // - * Construct the PDBEntry entry.setId(id); if (entry.getProperty() == null) - * entry.setProperty(new Hashtable()); entry.getProperty().put("chains", - * pdbchain.id + "=" + sq.getStart() + "-" + sq.getEnd()); - * sq.getDatasetSequence().addPDBId(entry); // Add PDB DB Refs // We make a - * DBRefEtntry because we have obtained the PDB file from a verifiable source - * // JBPNote - PDB DBRefEntry should also carry the chain and mapping - * information DBRefEntry dbentry = new - * DBRefEntry(jalview.datamodel.DBRefSource.PDB, "0", id + pdbchain.id); - * sq.addDBRef(dbentry); // and add seuqence to the retrieved set - * result.addElement(sq.deriveSequence()); } } - * - * if (result.size() < 1) { throw new Exception("WsDBFetch for PDB id resulted - * in zero result size"); } } catch (Exception ex) // Problem parsing PDB file - * { jalview.bin.Cache.log.warn("Exception when retrieving " + - * textArea.getText() + " from " + database.getSelectedItem(), ex); return - * null; } - * + /** + * Query for a single accession id via the database proxy * - * SequenceI[] results = new SequenceI[result.size()]; for (int i = 0, j = - * result.size(); i < j; i++) { results[i] = (SequenceI) result.elementAt(i); - * result.setElementAt(null,i); } return results; } + * @param proxy + * @param accession + * @param aresultq + * a list of successful queries to add to + * @param aresult + * a list of retrieved alignments to add to + * @return true if the fetch was successful, else false */ - AlignmentI parseResult(String result, String title) + boolean fetchSingleAccession(DbSourceProxy proxy, String accession, + List aresultq, List aresult) { - String format = new IdentifyFile().Identify(result, "Paste"); - Alignment sequences = null; - if (FormatAdapter.isValidFormat(format)) + boolean success = false; + try { - sequences = null; + if (aresult != null) + { + try + { + // give the server a chance to breathe + Thread.sleep(5); + } catch (Exception e) + { + // + } + } + + AlignmentI indres = null; try { - sequences = new FormatAdapter().readFile(result.toString(), - "Paste", format); - } catch (Exception ex) + indres = proxy.getSequenceRecords(accession); + } catch (OutOfMemoryError oome) { + new OOMWarning( + "fetching " + accession + " from " + proxy.getDbName(), + oome, this); } - - if (sequences != null) + if (indres != null) { - return parseResult(sequences, title, format); + aresultq.add(accession); + aresult.add(indres); + success = true; } - } - else + } catch (Exception e) { - showErrorMessage("Error retrieving " + textArea.getText() + " from " - + database.getSelectedItem()); + Cache.log.info("Error retrieving " + accession + " from " + + proxy.getDbName(), e); } + return success; + } + + /** + * Checks which of the queries were successfully retrieved by searching the + * DBRefs of the retrieved sequences for a match. Any not found are added to + * the 'nextFetch' list. + * + * @param rslt + * @param queries + * @param nextFetch + * @param proxy + */ + void checkResultForQueries(AlignmentI rslt, List queries, + List nextFetch, DbSourceProxy proxy) + { + SequenceI[] rs = rslt.getSequencesArray(); - return null; + for (String q : queries) + { + DBRefEntry dbr = new DBRefEntry(); + dbr.setSource(proxy.getDbSource()); + dbr.setVersion(null); + String accId = proxy.getAccessionIdFromQuery(q); + dbr.setAccessionId(accId); + boolean rfound = false; + for (int r = 0; r < rs.length; r++) + { + if (rs[r] != null) + { + List found = DBRefUtils.searchRefs(rs[r].getDBRefs(), + accId); + if (!found.isEmpty()) + { + rfound = true; + break; + } + } + } + if (!rfound) + { + nextFetch.add(q); + } + } } /** * - * @return a standard title for any results retrieved using the currently selected source and settings + * @return a standard title for any results retrieved using the currently + * selected source and settings */ - public String getDefaultRetrievalTitle() { + public String getDefaultRetrievalTitle() + { return "Retrieved from " + database.getSelectedItem(); } + AlignmentI parseResult(AlignmentI al, String title, - String currentFileFormat) + FileFormatI currentFileFormat, + FeatureSettingsModelI preferredFeatureColours) { if (al != null && al.getHeight() > 0) { + if (title == null) + { + title = getDefaultRetrievalTitle(); + } if (alignFrame == null) { AlignFrame af = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); if (currentFileFormat != null) { - af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT - // FORMAT FOR - // NON-FormatAdapter Sourced - // Alignments? + af.currentFileFormat = currentFileFormat; } - if (title == null) - { - title = getDefaultRetrievalTitle(); - } - SequenceFeature[] sfs = null; - for (Enumeration sq = al.getSequences().elements(); sq - .hasMoreElements();) + List alsqs = al.getSequences(); + synchronized (alsqs) { - if ((sfs = ((SequenceI) sq.nextElement()).getDatasetSequence() - .getSequenceFeatures()) != null) + for (SequenceI sq : alsqs) { - if (sfs.length > 0) + if (sq.getFeatures().hasFeatures()) { af.setShowSeqFeatures(true); break; } } + } + if (preferredFeatureColours != null) + { + af.getViewport().applyFeaturesStyle(preferredFeatureColours); + } + if (Cache.getDefault("HIDE_INTRONS", true)) + { + af.hideFeatureColumns(SequenceOntologyI.EXON, false); } Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - af.statusBar.setText("Successfully pasted alignment file"); + af.setStatus(MessageManager + .getString("label.successfully_pasted_alignment_file")); try { - af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", - false)); + af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false)); } catch (Exception ex) { } } else { - for (int i = 0; i < al.getHeight(); i++) - { - alignFrame.viewport.alignment.addSequence(al.getSequenceAt(i)); // this - // also - // creates - // dataset - // sequence - // entries - } - alignFrame.viewport.setEndSeq(alignFrame.viewport.alignment - .getHeight()); - alignFrame.viewport.alignment.getWidth(); - alignFrame.viewport.firePropertyChange("alignment", null, - alignFrame.viewport.getAlignment().getSequences()); + alignFrame.viewport.addAlignment(al, title); } } return al; @@ -818,11 +853,52 @@ public class SequenceFetcher extends JPanel implements Runnable resetDialog(); javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - JOptionPane.showInternalMessageDialog(Desktop.desktop, error, - "Error Retrieving Data", JOptionPane.WARNING_MESSAGE); + JvOptionPane.showInternalMessageDialog(Desktop.desktop, error, + MessageManager.getString("label.error_retrieving_data"), + JvOptionPane.WARNING_MESSAGE); } }); } + + public IProgressIndicator getProgressIndicator() + { + return progressIndicator; + } + + public void setProgressIndicator(IProgressIndicator progressIndicator) + { + this.progressIndicator = progressIndicator; + } + + /** + * Hide this panel (on clicking the database button to open the database + * chooser) + */ + void hidePanel() + { + frame.setVisible(false); + } + + public void setQuery(String ids) + { + textArea.setText(ids); + } + + /** + * Called to modify the search panel for embedding as an alternative tab of a + * free text search panel. The database choice list is hidden (since the + * choice has been made), and a Back button is made visible (which reopens the + * Sequence Fetcher panel). + * + * @param parentPanel + */ + public void embedIn(GFTSPanel parentPanel) + { + database.setVisible(false); + backBtn.setVisible(true); + parentSearchPanel = parentPanel; + } }