X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSequenceFetcher.java;h=9052413245c00b90607583422ea579adef03fa6b;hb=a1984b1c8c273ed33c7ce9283039f4027dcae2de;hp=ab78ad322ec0a6d866b8110648f1fa70fedbcfe5;hpb=007af0c9001900071f6d8e9214143f79e10f4938;p=jalview.git diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index ab78ad3..9052413 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -20,20 +20,6 @@ */ package jalview.gui; -import jalview.api.FeatureSettingsModelI; -import jalview.bin.Cache; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.DBRefEntry; -import jalview.datamodel.SequenceFeature; -import jalview.datamodel.SequenceI; -import jalview.fts.service.pdb.PDBFTSPanel; -import jalview.fts.service.uniprot.UniprotFTSPanel; -import jalview.io.gff.SequenceOntologyI; -import jalview.util.DBRefUtils; -import jalview.util.MessageManager; -import jalview.ws.dbsources.das.api.DasSourceRegistryI; -import jalview.ws.seqfetcher.DbSourceProxy; - import java.awt.BorderLayout; import java.awt.Font; import java.awt.event.ActionEvent; @@ -42,57 +28,101 @@ 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.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingConstants; -import javax.swing.tree.DefaultMutableTreeNode; +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.threedbeacons.TDBeaconsFTSPanel; +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; + +/** + * 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 { - JLabel dbeg = new JLabel(); - - JDatabaseTree database; + private class StringPair + { + private String key; - JButton databaseButt; + private String display; - JLabel jLabel1 = new JLabel(); + public StringPair(String s1, String s2) + { + key = s1; + display = s2; + } - JCheckBox replacePunctuation = new JCheckBox(); + public StringPair(String s) + { + this(s, s); + } - JButton ok = new JButton(); + public String getKey() + { + return key; + } - JButton clear = new JButton(); + public String getDisplay() + { + return display; + } - JButton example = new JButton(); + @Override + public String toString() + { + return display; + } - JButton close = new JButton(); + public boolean equals(StringPair other) + { + return other.key == this.key; + } + } - JPanel jPanel1 = new JPanel(); + private static jalview.ws.SequenceFetcher sfetch = null; - JTextArea textArea = new JTextArea(); + JLabel exampleAccession; - JScrollPane jScrollPane1 = new JScrollPane(); + JComboBox database; - JPanel jPanel2 = new JPanel(); + JCheckBox replacePunctuation; - JPanel jPanel3 = new JPanel(); + JButton okBtn; - JPanel jPanel4 = new JPanel(); + JButton exampleBtn; - BorderLayout borderLayout1 = new BorderLayout(); + JButton closeBtn; - BorderLayout borderLayout2 = new BorderLayout(); + JButton backBtn; - BorderLayout borderLayout3 = new BorderLayout(); + JTextArea textArea; JInternalFrame frame; @@ -100,215 +130,147 @@ public class SequenceFetcher extends JPanel implements Runnable AlignFrame alignFrame; - StringBuffer result; + GFTSPanel parentSearchPanel; - final String noDbSelected = "-- Select Database --"; - - private static jalview.ws.SequenceFetcher sfetch = null; + IProgressIndicator progressIndicator; - private static long lastDasSourceRegistry = -3; - - private static DasSourceRegistryI dasRegistry = null; - - private static boolean _initingFetcher = false; - - private static Thread initingThread = null; - - int debounceTrap = 0; - - public JTextArea getTextArea() - { - return textArea; - } + 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 (sfetch == null) { - if (guiWindow != null) - { - guiWindow - .setProgressBar( - MessageManager - .getString("status.waiting_sequence_database_fetchers_init"), - 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( - MessageManager - .getString("status.waiting_sequence_database_fetchers_init"), - Thread.currentThread().hashCode()); - } - } - if (sfetch == null - || dasRegistry != Cache.getDasSourceRegistry() - || lastDasSourceRegistry != (Cache.getDasSourceRegistry() - .getDasRegistryURL() + Cache - .getDasSourceRegistry().getLocalSourceString()) - .hashCode()) - { - _initingFetcher = true; - initingThread = Thread.currentThread(); - /** - * give a visual indication that sequence fetcher construction is occuring - */ - if (guiWindow != null) - { - guiWindow.setProgressBar(MessageManager - .getString("status.init_sequence_database_fetchers"), - Thread.currentThread().hashCode()); - } - dasRegistry = Cache.getDasSourceRegistry(); - dasRegistry.refreshSources(); - - jalview.ws.SequenceFetcher sf = new jalview.ws.SequenceFetcher(); - if (guiWindow != null) - { - guiWindow.setProgressBar(null, Thread.currentThread().hashCode()); - } - lastDasSourceRegistry = (dasRegistry.getDasRegistryURL() + dasRegistry - .getLocalSourceString()).hashCode(); - sfetch = sf; - _initingFetcher = false; - initingThread = null; + sfetch = new jalview.ws.SequenceFetcher(); } return sfetch; } - private IProgressIndicator progressIndicator; - + /** + * 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) { - this.progressIndicator = guiIndic; - final SequenceFetcher us = this; - // launch initialiser thread - Thread sf = new Thread(new Runnable() - { - - @Override - public void run() - { - if (getSequenceFetcherSingleton(progressIndicator) != null) - { - us.initGui(progressIndicator); - } - else - { - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - JOptionPane - .showInternalMessageDialog( - Desktop.desktop, - MessageManager - .getString("warn.couldnt_create_sequence_fetcher_client"), - MessageManager - .getString("label.couldnt_create_sequence_fetcher"), - JOptionPane.ERROR_MESSAGE); - } - }); - - // raise warning dialog - } - } - }); - sf.start(); + this(guiIndic, null, null); } - private class DatabaseAuthority extends DefaultMutableTreeNode - { - - }; - - private class DatabaseSource extends DefaultMutableTreeNode - { - - }; - /** - * 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; - } - database = new JDatabaseTree(sfetch); - try - { - jbInit(); - } catch (Exception ex) + this.progressIndicator = guiIndic; + getSequenceFetcherSingleton(); + this.guiWindow = progressIndicator; + + if (progressIndicator instanceof AlignFrame) { - 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); - } + Desktop.addInternalFrame(frame, getFrameTitle(), true, 400, + Platform.isAMacAndNotJS() ? 240 : 180); } private String getFrameTitle() { - return ((alignFrame == null) ? MessageManager - .getString("label.new_sequence_fetcher") : MessageManager - .getString("label.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)); - jLabel1.setHorizontalAlignment(SwingConstants.CENTER); - jLabel1.setText(MessageManager - .getString("label.separate_multiple_accession_ids")); + StringPair instructionItem = new StringPair( + MessageManager.getString("action.select_ddbb")); + database.setPrototypeDisplayValue(instructionItem); + String[] sources = new jalview.ws.SequenceFetcher().getSupportedDb(); + Arrays.sort(sources, String.CASE_INSENSITIVE_ORDER); + database.addItem(instructionItem); + for (String source : sources) + { + List slist = sfetch.getSourceProxy(source); + if (slist.size() == 1 && slist.get(0) != null) + { + database.addItem(new StringPair(source, slist.get(0).getDbName())); + } + else + { + database.addItem(new StringPair(source)); + } + } + setDatabaseSelectedItem(selectedDb); + if (database.getSelectedIndex() == -1) + { + database.setSelectedIndex(0); + } + database.setMaximumRowCount(database.getItemCount()); + database.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + String currentSelection = ((StringPair) database.getSelectedItem()) + .getKey(); + updateExampleQuery(currentSelection); - replacePunctuation.setHorizontalAlignment(SwingConstants.CENTER); - replacePunctuation - .setFont(new java.awt.Font("Verdana", Font.ITALIC, 11)); - replacePunctuation.setText(MessageManager - .getString("label.replace_commas_semicolons")); - ok.setText(MessageManager.getString("action.ok")); - ok.addActionListener(new ActionListener() + if ("pdb".equalsIgnoreCase(currentSelection)) + { + frame.dispose(); + new PDBFTSPanel(SequenceFetcher.this); + } + else if ("uniprot".equalsIgnoreCase(currentSelection)) + { + frame.dispose(); + new UniprotFTSPanel(SequenceFetcher.this); + } + else if ("3d-beacons".equalsIgnoreCase(currentSelection)) + { + frame.dispose(); + new TDBeaconsFTSPanel(SequenceFetcher.this); + } + 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.LEFT); + + replacePunctuation = new JCheckBox( + MessageManager.getString("label.replace_commas_semicolons")); + replacePunctuation.setHorizontalAlignment(SwingConstants.LEFT); + 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) @@ -316,7 +278,7 @@ public class SequenceFetcher extends JPanel implements Runnable ok_actionPerformed(); } }); - clear.setText(MessageManager.getString("action.clear")); + JButton clear = new JButton(MessageManager.getString("action.clear")); clear.addActionListener(new ActionListener() { @Override @@ -326,8 +288,8 @@ public class SequenceFetcher extends JPanel implements Runnable } }); - example.setText(MessageManager.getString("label.example")); - example.addActionListener(new ActionListener() + exampleBtn = new JButton(MessageManager.getString("label.example")); + exampleBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) @@ -335,8 +297,8 @@ public class SequenceFetcher extends JPanel implements Runnable example_actionPerformed(); } }); - close.setText(MessageManager.getString("action.close")); - close.addActionListener(new ActionListener() + closeBtn = new JButton(MessageManager.getString("action.cancel")); + closeBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) @@ -344,6 +306,19 @@ public class SequenceFetcher extends JPanel implements Runnable 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() @@ -357,136 +332,193 @@ public class SequenceFetcher extends JPanel implements Runnable } } }); - 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); - databaseButt = database.getDatabaseSelectorButton(); - databaseButt.setFont(JvSwingUtils.getLabelFont()); - database.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - debounceTrap++; - String currentSelection = database.getSelectedItem(); - - if (currentSelection.equalsIgnoreCase("pdb") - && (database.action == KeyEvent.VK_ENTER || ((debounceTrap % 2) == 0))) - { - pdbSourceAction(); - } - else if (currentSelection.equalsIgnoreCase("uniprot") - && (database.action == KeyEvent.VK_ENTER || ((debounceTrap % 2) == 0))) - { - uniprotSourceAction(); - } - else - { - otherSourceAction(); - } - database.action = -1; - } - }); - dbeg.setText(""); - jPanel2.add(databaseButt, java.awt.BorderLayout.NORTH); - jPanel2.add(dbeg, java.awt.BorderLayout.CENTER); + 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, 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); + jPanel2a.add(jLabel1, BorderLayout.NORTH); + jPanel2a.add(replacePunctuation, BorderLayout.SOUTH); + databasePanel.add(jPanel2a, BorderLayout.SOUTH); + + 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); } - private void pdbSourceAction() + private void setDatabaseSelectedItem(String db) { - databaseButt.setText(database.getSelectedItem()); - new PDBFTSPanel(this); - frame.dispose(); + for (int i = 0; i < database.getItemCount(); i++) + { + StringPair sp = database.getItemAt(i); + if (sp != null && db != null && db.equals(sp.getKey())) + { + database.setSelectedIndex(i); + return; + } + } } - private void uniprotSourceAction() - { - databaseButt.setText(database.getSelectedItem()); - new UniprotFTSPanel(this); - frame.dispose(); - } - private void otherSourceAction() + /** + * Answers a semi-colon-delimited string with the example query or queries for + * the selected database + * + * @param db + * @return + */ + protected String getExampleQueries(String db) { - try + StringBuilder sb = new StringBuilder(); + HashSet hs = new HashSet<>(); + for (DbSourceProxy dbs : sfetch.getSourceProxy(db)) { - databaseButt.setText(database.getSelectedItem() - + (database.getSelectedSources().size() > 1 ? " (and " - + database.getSelectedSources().size() + " others)" - : "")); - String eq = database.getExampleQueries(); - dbeg.setText(MessageManager.formatMessage( - "label.example_query_param", new String[] { eq })); - boolean enablePunct = !(eq != null && eq.indexOf(",") > -1); - for (DbSourceProxy dbs : database.getSelectedSources()) + String tq = dbs.getTestQuery(); + if (hs.add(tq)) // not a duplicate source { - if (dbs instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource) + if (sb.length() > 0) { - enablePunct = false; - break; + sb.append(";"); } + sb.append(tq); } + } + return sb.toString(); + } + + /** + * 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() + { + try + { + 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) { - dbeg.setText(""); + exampleAccession.setText(""); replacePunctuation.setEnabled(true); } - jPanel2.repaint(); + repaint(); + } + + /** + * 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) + { + String eq = getExampleQueries(selectedDatabase); + exampleAccession.setText(MessageManager + .formatMessage("label.example_query_param", new String[] + { eq })); + return eq; } + /** + * Action on clicking the 'Example' button is to write the example accession + * as the query text field value + */ protected void example_actionPerformed() { - DbSourceProxy db = null; - try - { - textArea.setText(database.getExampleQueries()); - } catch (Exception ex) - { - } - jPanel3.repaint(); + String eq = getExampleQueries( + ((StringPair) database.getSelectedItem()).getKey()); + textArea.setText(eq); + repaint(); } + /** + * Clears the query input field + */ protected void clear_actionPerformed() { textArea.setText(""); - jPanel3.repaint(); + 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() { - databaseButt.setEnabled(false); - example.setEnabled(false); + /* + * tidy inputs and check there is something to search for + */ + String t0 = textArea.getText(); + String text = t0.trim(); + if (replacePunctuation.isEnabled() && replacePunctuation.isSelected()) + { + text = text.replace(",", ";"); + } + text = text.replaceAll("(\\s|[; ])+", ";"); + if (!t0.equals(text)) + { + textArea.setText(text); + } + if (text.isEmpty()) + { + // todo i18n + showErrorMessage( + "Please enter a (semi-colon separated list of) database id(s)"); + resetDialog(); + return; + } + if (database.getSelectedIndex() == 0) + { + // todo i18n + showErrorMessage("Please choose a database"); + 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(); @@ -494,225 +526,96 @@ public class SequenceFetcher extends JPanel implements Runnable private void resetDialog() { - databaseButt.setEnabled(true); - example.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.hasSelection()) - { - 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; - } - // TODO: Refactor to GUI independent code and write tests. - // indicate if successive sources should be merged into one alignment. boolean addToLast = false; - ArrayList aresultq = new ArrayList(), presultTitle = new ArrayList(); - ArrayList presult = new ArrayList(), aresult = new ArrayList(); - Iterator proxies = database.getSelectedSources() - .iterator(); - String[] qries; - List nextfetch = Arrays.asList(qries = textArea.getText() - .split(";")); + List aresultq = new ArrayList<>(); + List presultTitle = new ArrayList<>(); + List presult = new ArrayList<>(); + List aresult = new ArrayList<>(); + List sources = sfetch.getSourceProxy( + ((StringPair) database.getSelectedItem()).getKey()); + Iterator proxies = sources.iterator(); + String[] qries = textArea.getText().trim().split(";"); + List nextFetch = Arrays.asList(qries); Iterator en = Arrays.asList(new String[0]).iterator(); int nqueries = qries.length; FeatureSettingsModelI preferredFeatureColours = null; - while (proxies.hasNext() && (en.hasNext() || nextfetch.size() > 0)) + while (proxies.hasNext() && (en.hasNext() || nextFetch.size() > 0)) { - if (!en.hasNext() && nextfetch.size() > 0) + if (!en.hasNext() && nextFetch.size() > 0) { - en = nextfetch.iterator(); - nqueries = nextfetch.size(); + en = nextFetch.iterator(); + nqueries = nextFetch.size(); // save the remaining queries in the original array - qries = nextfetch.toArray(new String[nqueries]); - nextfetch = new ArrayList(); + qries = nextFetch.toArray(new String[nqueries]); + nextFetch = new ArrayList<>(); } DbSourceProxy proxy = proxies.next(); - boolean isAliSource = false; try { // update status - guiWindow - .setProgressBar(MessageManager.formatMessage( - "status.fetching_sequence_queries_from", - new String[] { - Integer.valueOf(nqueries).toString(), - proxy.getDbName() }), Thread.currentThread() - .hashCode()); - isAliSource = proxy.isAlignmentSource(); + guiWindow.setProgressBar(MessageManager.formatMessage( + "status.fetching_sequence_queries_from", new String[] + { Integer.valueOf(nqueries).toString(), + proxy.getDbName() }), + Thread.currentThread().hashCode()); if (proxy.getMaximumQueryCount() == 1) { + /* + * proxy only handles one accession id at a time + */ while (en.hasNext()) { - String item = en.next(); - try - { - if (aresult != null) - { - try - { - // give the server a chance to breathe - Thread.sleep(5); - } catch (Exception e) - { - // - } - - } - - AlignmentI indres = null; - try - { - indres = proxy.getSequenceRecords(item); - } catch (OutOfMemoryError oome) - { - new OOMWarning("fetching " + item + " from " - + proxy.getDbName(), oome, this); - } - if (indres != null) - { - aresultq.add(item); - aresult.add(indres); - } - else - { - nextfetch.add(item); - } - } catch (Exception e) + String acc = en.next(); + if (!fetchSingleAccession(proxy, acc, aresultq, aresult)) { - Cache.log.info( - "Error retrieving " + item - + " from " + proxy.getDbName(), e); - nextfetch.add(item); + nextFetch.add(acc); } } } else { - StringBuffer multiacc = new StringBuffer(); - ArrayList tosend = new ArrayList(); - while (en.hasNext()) - { - String nel = en.next(); - tosend.add(nel); - multiacc.append(nel); - if (en.hasNext()) - { - multiacc.append(proxy.getAccessionSeparator()); - } - } - try - { - AlignmentI rslt; - SequenceI[] rs; - List nores = new ArrayList(); - rslt = proxy.getSequenceRecords(multiacc.toString()); - if (rslt == null || rslt.getHeight() == 0) - { - // no results - pass on all queries to next source - nextfetch.addAll(tosend); - } - else - { - aresultq.add(multiacc.toString()); - aresult.add(rslt); - - rs = rslt.getSequencesArray(); - // search for each query in the dbrefs associated with each - // sequence - // returned. - // ones we do not find will be used to query next source (if any) - for (String q : tosend) - { - DBRefEntry dbr = new DBRefEntry(), found[] = null; - 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) - { - found = DBRefUtils.searchRefs(rs[r].getDBRefs(), accId); - if (found != null && found.length > 0) - { - rfound = true; - rs[r] = null; - } - } - } - if (!rfound) - { - nextfetch.add(q); - } - } - } - } catch (OutOfMemoryError oome) - { - new OOMWarning("fetching " + multiacc + " from " - + database.getSelectedItem(), oome, this); - } + /* + * 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()); + showErrorMessage("Error retrieving " + textArea.getText() + " from " + + ((StringPair) database.getSelectedItem()).getDisplay()); // error // +="Couldn't retrieve sequences from "+database.getSelectedItem(); System.err.println("Retrieval failed for source ='" - + database.getSelectedItem() + "' and query\n'" - + textArea.getText() + "'\n"); + + ((StringPair) database.getSelectedItem()).getDisplay() + + "' 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() + + textArea.getText() + " from " + + ((StringPair) database.getSelectedItem()).getDisplay() + "\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()); + + " from " + + ((StringPair) database.getSelectedItem()).getDisplay()); e.printStackTrace(); } + // Stack results ready for opening in alignment windows if (aresult != null && aresult.size() > 0) { @@ -724,15 +627,15 @@ public class SequenceFetcher extends JPanel implements Runnable } AlignmentI ar = null; - if (isAliSource) + 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()); + presultTitle.add( + aresultq.remove(0) + " " + getDefaultRetrievalTitle()); } } else @@ -754,22 +657,23 @@ public class SequenceFetcher extends JPanel implements Runnable { ar.append(aresult.remove(0)); } - ; } addToLast = true; presult.add(ar); presultTitle.add(titl); } } - guiWindow.setProgressBar(MessageManager - .getString("status.finshed_querying"), Thread.currentThread() - .hashCode()); + 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()); + guiWindow + .setProgressBar( + (presult.size() > 0) + ? MessageManager + .getString("status.parsing_results") + : MessageManager.getString("status.processing"), + Thread.currentThread().hashCode()); // process results while (presult.size() > 0) { @@ -778,14 +682,15 @@ public class SequenceFetcher extends JPanel implements Runnable } // only remove visual delay after we finished parsing. guiWindow.setProgressBar(null, Thread.currentThread().hashCode()); - if (nextfetch.size() > 0) + if (nextFetch.size() > 0) { StringBuffer sb = new StringBuffer(); sb.append("Didn't retrieve the following " - + (nextfetch.size() == 1 ? "query" : nextfetch.size() - + " queries") + ": \n"); + + (nextFetch.size() == 1 ? "query" + : nextFetch.size() + " queries") + + ": \n"); int l = sb.length(), lr = 0; - for (String s : nextfetch) + for (String s : nextFetch) { if (l != sb.length()) { @@ -803,17 +708,181 @@ public class SequenceFetcher extends JPanel implements Runnable } /** + * 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()); + } + } + + try + { + 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) + { + checkResultForQueries(rslt, tosend, nextFetch, proxy); + } + } + } catch (OutOfMemoryError oome) + { + new OOMWarning("fetching " + multiacc + " from " + + ((StringPair) database.getSelectedItem()).getDisplay(), + oome, this); + } + } + + /** + * Query for a single accession id via the database proxy + * + * @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 + */ + boolean fetchSingleAccession(DbSourceProxy proxy, String accession, + List aresultq, List aresult) + { + boolean success = false; + try + { + if (aresult != null) + { + try + { + // give the server a chance to breathe + Thread.sleep(5); + } catch (Exception e) + { + // + } + } + + AlignmentI indres = null; + try + { + indres = proxy.getSequenceRecords(accession); + } catch (OutOfMemoryError oome) + { + new OOMWarning( + "fetching " + accession + " from " + proxy.getDbName(), + oome, this); + } + if (indres != null) + { + aresultq.add(accession); + aresult.add(indres); + success = true; + } + } catch (Exception e) + { + Cache.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(); + + for (String q : queries) + { + // BH 2019.01.25 dbr is never used. + // 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, nr = rs.length; r < nr; 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 */ public String getDefaultRetrievalTitle() { - return "Retrieved from " + database.getSelectedItem(); + return "Retrieved from " + + ((StringPair) database.getSelectedItem()).getDisplay(); } - AlignmentI parseResult(AlignmentI al, String title, - String currentFileFormat, + /** + * constructs an alignment frame given the data and metadata + * + * @param al + * @param title + * @param currentFileFormat + * @param preferredFeatureColours + * @return the alignment + */ + public AlignmentI parseResult(AlignmentI al, String title, + FileFormatI currentFileFormat, FeatureSettingsModelI preferredFeatureColours) { @@ -829,49 +898,36 @@ public class SequenceFetcher extends JPanel implements Runnable AlignFrame.DEFAULT_HEIGHT); if (currentFileFormat != null) { - af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT - // FORMAT FOR - // NON-FormatAdapter Sourced - // Alignments? + af.currentFileFormat = currentFileFormat; } - SequenceFeature[] sfs = null; - List alsqs; - synchronized (alsqs = al.getSequences()) + List alsqs = al.getSequences(); + synchronized (alsqs) { for (SequenceI sq : alsqs) { - if ((sfs = sq.getSequenceFeatures()) != null) + if (sq.getFeatures().hasFeatures()) { - if (sfs.length > 0) - { - af.setShowSeqFeatures(true); - break; - } + af.setShowSeqFeatures(true); + break; } - } } - if (preferredFeatureColours != null) - { - af.getViewport().applyFeaturesStyle(preferredFeatureColours); - } + af.getViewport().applyFeaturesStyle(preferredFeatureColours); if (Cache.getDefault("HIDE_INTRONS", true)) { - hideIntronsIfPresent(af); + af.hideFeatureColumns(SequenceOntologyI.EXON, false); } - Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - af.statusBar.setText(MessageManager + af.setStatus(MessageManager .getString("label.successfully_pasted_alignment_file")); try { - af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", - false)); + af.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false)); } catch (Exception ex) { } @@ -884,25 +940,6 @@ public class SequenceFetcher extends JPanel implements Runnable return al; } - /** - * Hide columns not containing 'exon' features, provided there are exon - * features on the alignment - * - * @param af - */ - public void hideIntronsIfPresent(AlignFrame af) - { - boolean hasExons = af.avc.markColumnsContainingFeatures(false, false, - false, - SequenceOntologyI.EXON); - if (hasExons) - { - af.avc.markColumnsContainingFeatures(true, false, true, - SequenceOntologyI.EXON); - af.getViewport().hideSelectedColumns(); - } - } - void showErrorMessage(final String error) { resetDialog(); @@ -911,9 +948,9 @@ public class SequenceFetcher extends JPanel implements Runnable @Override public void run() { - JOptionPane.showInternalMessageDialog(Desktop.desktop, error, + JvOptionPane.showInternalMessageDialog(Desktop.desktop, error, MessageManager.getString("label.error_retrieving_data"), - JOptionPane.WARNING_MESSAGE); + JvOptionPane.WARNING_MESSAGE); } }); } @@ -927,4 +964,33 @@ public class SequenceFetcher extends JPanel implements Runnable { 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; + } }