From: gmungoc Date: Wed, 25 Mar 2015 13:46:16 +0000 (+0000) Subject: Merge branch 'develop' of https://source.jalview.org/git/jalview.git into develop X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=2476d30e443b80cddbc953dd5285968a964eb42a;hp=f18077aa57dea5481ae537162871045f8557e2f0;p=jalview.git Merge branch 'develop' of https://source.jalview.org/git/jalview.git into develop --- diff --git a/.classpath b/.classpath index c3e70c0..c19e381 100644 --- a/.classpath +++ b/.classpath @@ -56,6 +56,10 @@ + + + + diff --git a/lib/jersey-client-1.19.jar b/lib/jersey-client-1.19.jar new file mode 100644 index 0000000..c9e0f56 Binary files /dev/null and b/lib/jersey-client-1.19.jar differ diff --git a/lib/jersey-core-1.19.jar b/lib/jersey-core-1.19.jar new file mode 100644 index 0000000..92feb63 Binary files /dev/null and b/lib/jersey-core-1.19.jar differ diff --git a/lib/jersey-json-1.19.jar b/lib/jersey-json-1.19.jar new file mode 100644 index 0000000..b609411 Binary files /dev/null and b/lib/jersey-json-1.19.jar differ diff --git a/lib/jsr311-api-1.1.1.jar b/lib/jsr311-api-1.1.1.jar new file mode 100644 index 0000000..ec8bc81 Binary files /dev/null and b/lib/jsr311-api-1.1.1.jar differ diff --git a/resources/images/dna.png b/resources/images/dna.png new file mode 100644 index 0000000..f9854fe Binary files /dev/null and b/resources/images/dna.png differ diff --git a/resources/images/error.png b/resources/images/error.png new file mode 100644 index 0000000..6d68a8c Binary files /dev/null and b/resources/images/error.png differ diff --git a/resources/images/good.png b/resources/images/good.png new file mode 100644 index 0000000..ebbacc9 Binary files /dev/null and b/resources/images/good.png differ diff --git a/resources/images/loading.gif b/resources/images/loading.gif new file mode 100644 index 0000000..23ed238 Binary files /dev/null and b/resources/images/loading.gif differ diff --git a/resources/images/protein.png b/resources/images/protein.png new file mode 100644 index 0000000..3789793 Binary files /dev/null and b/resources/images/protein.png differ diff --git a/resources/images/sugar.png b/resources/images/sugar.png new file mode 100644 index 0000000..5d62ce5 Binary files /dev/null and b/resources/images/sugar.png differ diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index e6b69d5..0d3d491 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -783,7 +783,6 @@ label.use_sequence_id_1 = Use $SEQUENCE_ID$ or $SEQUENCE_ID=//=$ label.use_sequence_id_2 = \nto embed sequence id in URL label.ws_parameters_for = Parameters for {0} label.switch_server = Switch server -label.open_jabaws_web_page = Opens the JABAWS server's homepage in web browser label.choose_jabaws_server = Choose a server for running this service label.services_at = Services at {0} label.rest_client_submit = {0} using {1} @@ -1207,5 +1206,22 @@ label.search_filter = Search Filter label.display_name = Display Label label.description = Description label.include_description= Include Description +action.back = Back +label.hide_insertions = Hide Insertions +label.mark_as_representative = Mark as representative +label.open_jabaws_web_page = Open JABAWS web page +label.opens_the_jabaws_server_homepage = Opens the JABAWS server's homepage in web browser +label.pdb_sequence_getcher = PDB Sequence Fetcher +label.result = result +label.results = results +label.structure_chooser = Structure Chooser +label.select = Select : +label.invert = Invert +label.select_pdb_file = Select PDB File +info.select_filter_option = Select Filter Option/Manual Entry +info.associate_wit_sequence = Associate with Sequence +label.search_result = Search Result +label.found_structures_summary = Found Structures Summary +label.configure_displayed_columns = Configure Displayed Columns label.start_jalview = Start Jalview label.biojs_html_export = BioJS diff --git a/src/jalview/gui/PDBSearchPanel.java b/src/jalview/gui/PDBSearchPanel.java new file mode 100644 index 0000000..2d46714 --- /dev/null +++ b/src/jalview/gui/PDBSearchPanel.java @@ -0,0 +1,173 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) + * Copyright (C) 2014 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. + * + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +package jalview.gui; + +import jalview.jbgui.GPDBSearchPanel; +import jalview.jbgui.PDBDocFieldPreferences; +import jalview.util.MessageManager; +import jalview.ws.dbsources.PDBRestClient; +import jalview.ws.dbsources.PDBRestClient.PDBDocField; +import jalview.ws.uimodel.PDBRestRequest; +import jalview.ws.uimodel.PDBRestResponse; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import javax.swing.table.DefaultTableModel; + +@SuppressWarnings("serial") +public class PDBSearchPanel extends GPDBSearchPanel +{ + private SequenceFetcher seqFetcher; + + private IProgressIndicator progressIdicator; + + private Collection wantedFields; + + public PDBSearchPanel(SequenceFetcher seqFetcher) + { + this.seqFetcher = seqFetcher; + this.progressIdicator = (seqFetcher == null) ? null : seqFetcher + .getProgressIndicator(); + } + + + /** + * Action performed when an input is detected on txt_search field. + */ + @Override + public void txt_search_ActionPerformed() + { + boolean allowEmptySequence = false; + mainFrame.setTitle(MessageManager + .getString("label.pdb_sequence_getcher")); + tbl_summary.setModel(new DefaultTableModel()); + if (txt_search.getText().trim().length() > 0) + { + long startTime = System.currentTimeMillis(); + + String searchTarget = ((PDBDocField) cmb_searchTarget + .getSelectedItem()).getCode(); + + wantedFields = PDBDocFieldPreferences + .getSearchSummaryFields(); + + PDBRestRequest request = new PDBRestRequest(); + request.setAllowEmptySeq(allowEmptySequence); + request.setResponseSize(100); + request.setFieldToSearchBy(searchTarget + ":"); + request.setSearchTerm(txt_search.getText()); + request.setWantedFields(wantedFields); + + PDBRestClient pdbRestCleint = new PDBRestClient(); + PDBRestResponse resultList = pdbRestCleint.executeRequest(request); + if (resultList.getSearchSummary() != null) + { + tbl_summary.setModel(PDBRestResponse.getTableModel(request, + resultList.getSearchSummary())); + } + + long endTime = System.currentTimeMillis(); + int resultSetCount = resultList.getNumberOfItemsFound(); + String result = (resultSetCount > 1) ? MessageManager + .getString("label.results") : MessageManager + .getString("label.result"); + mainFrame.setTitle(frameTitle + " - " + resultSetCount + " " + result + + " (" + (endTime - startTime) + " milli secs)"); + } + } + + @Override + public void btn_ok_ActionPerformed() + { + loadSelectedPDBSequencesToAlignment(); + } + + @Override + public void btn_back_ActionPerformed() + { + mainFrame.dispose(); + new SequenceFetcher(progressIdicator); + } + + @Override + public void btn_cancel_ActionPerformed() + { + mainFrame.dispose(); + } + + /** + * Add the discovered/selected sequences to a target alignment window + */ + public void loadSelectedPDBSequencesToAlignment() + { + mainFrame.dispose(); + StringBuilder selectedIds = new StringBuilder(); + int pdbIdCol = PDBRestClient.getPDBIdColumIndex(wantedFields, false); + int[] selectedRows = tbl_summary.getSelectedRows(); + for (int summaryRow : selectedRows) + { + String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol) + .toString(); + selectedIds.append(";").append(pdbIdStr); + } + + String ids = selectedIds.deleteCharAt(0).toString(); + seqFetcher.textArea.setText(ids); + Thread worker = new Thread(seqFetcher); + worker.start(); + } + + /** + * Populates search target combo-box options + */ + public void populateCmbSearchTargetOptions() + { + List searchableTargets = new ArrayList(); + searchableTargets.add(PDBDocField.PDB_ID); + searchableTargets.add(PDBDocField.PFAM_ACCESSION); + searchableTargets.add(PDBDocField.MOLECULE_TYPE); + searchableTargets.add(PDBDocField.MOLECULE_NAME); + searchableTargets.add(PDBDocField.UNIPROT_ACCESSION); + searchableTargets.add(PDBDocField.GENE_NAME); + searchableTargets.add(PDBDocField.GENUS); + searchableTargets.add(PDBDocField.ALL); + + Collections.sort(searchableTargets, new Comparator() + { + @Override + public int compare(PDBDocField o1, PDBDocField o2) + { + return o1.getName().compareTo(o2.getName()); + } + }); + + for (PDBDocField searchTarget : searchableTargets) + { + cmb_searchTarget.addItem(searchTarget); + } + } + +} diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 174772c..1263b71 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -124,9 +124,6 @@ public class PopupMenu extends JPopupMenu protected JRadioButtonMenuItem RNAInteractionColour = new JRadioButtonMenuItem(); - // protected JRadioButtonMenuItem covariationColour = new - // JRadioButtonMenuItem(); - JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem(); protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem(); @@ -181,12 +178,6 @@ public class PopupMenu extends JPopupMenu JMenuItem pdbFromFile = new JMenuItem(); - // JBPNote: Commented these out - Should add these services via the web - // services menu system. - // JMenuItem ContraFold = new JMenuItem(); - - // JMenuItem RNAFold = new JMenuItem(); - JMenuItem enterPDB = new JMenuItem(); JMenuItem discoverPDB = new JMenuItem(); @@ -213,15 +204,12 @@ public class PopupMenu extends JPopupMenu JMenu jMenu1 = new JMenu(); - JMenu structureMenu = new JMenu(); + JMenuItem structureMenu = new JMenuItem(); JMenu viewStructureMenu = new JMenu(); - // JMenu colStructureMenu = new JMenu(); JMenuItem editSequence = new JMenuItem(); - // JMenuItem annotationMenuItem = new JMenuItem(); - JMenu groupLinksMenu; JMenuItem hideInsertions = new JMenuItem(); @@ -274,7 +262,6 @@ public class PopupMenu extends JPopupMenu colours.add(BLOSUM62Colour); colours.add(purinePyrimidineColour); colours.add(RNAInteractionColour); - // colours.add(covariationColour); for (int i = 0; i < jalview.io.FormatAdapter.WRITEABLE_FORMATS.length; i++) { @@ -379,7 +366,6 @@ public class PopupMenu extends JPopupMenu { structureMenu.remove(viewStructureMenu); } - // structureMenu.remove(colStructureMenu); } if (ap.av.getAlignment().isNucleotide() == true) { @@ -400,19 +386,8 @@ public class PopupMenu extends JPopupMenu @Override public void actionPerformed(ActionEvent e) { - // // System.out.println("1:"+structureLine); - // System.out.println("1:sname" + seq.getName()); - // System.out.println("2:seq" + seq); - // - // // System.out.println("3:"+seq.getSequenceAsString()); - // System.out.println("3:strucseq" + rnastruc); - // // System.out.println("4:struc"+seq.getRNA()); - // System.out.println("5:name" + seq.getName()); - // System.out.println("6:ap" + ap); new AppVarna(structureLine, seq, seq.getSequenceAsString(), rnastruc, seq.getName(), ap); - // new AppVarna(seq.getName(),seq,rnastruc,seq.getRNA(), - // seq.getName(), ap); System.out.println("end"); } }); @@ -420,7 +395,6 @@ public class PopupMenu extends JPopupMenu } } - // SequenceFeatures[] test = seq.getSequenceFeatures(); if (seq.getAnnotation() != null) { @@ -640,50 +614,6 @@ public class PopupMenu extends JPopupMenu new PDBEntry[pdbe.size()]), pr = reppdb.values().toArray( new PDBEntry[reppdb.size()]); final JMenuItem gpdbview, rpdbview; - if (pdbe.size() == 1) - { - structureMenu.add(gpdbview = new JMenuItem(MessageManager - .formatMessage("label.view_structure_for", new Object[] - { sqass.getDisplayId(false) }))); - } - else - { - structureMenu.add(gpdbview = new JMenuItem(MessageManager - .formatMessage("label.view_all_structures", new Object[] - { new Integer(pdbe.size()).toString() }))); - } - gpdbview.setToolTipText(MessageManager - .getString("label.open_new_jmol_view_with_all_structures_associated_current_selection_superimpose_using_alignment")); - gpdbview.addActionListener(new ActionListener() - { - - @Override - public void actionPerformed(ActionEvent e) - { - new StructureViewer(ap.getStructureSelectionManager()) - .viewStructures(ap, pe, ap.av.collateForPDB(pe)); - } - }); - if (reppdb.size() > 1 && reppdb.size() < pdbe.size()) - { - structureMenu.add(rpdbview = new JMenuItem(MessageManager - .formatMessage( - "label.view_all_representative_structures", - new Object[] - { new Integer(reppdb.size()).toString() }))); - rpdbview.setToolTipText(MessageManager - .getString("label.open_new_jmol_view_with_all_representative_structures_associated_current_selection_superimpose_using_alignment")); - rpdbview.addActionListener(new ActionListener() - { - - @Override - public void actionPerformed(ActionEvent e) - { - new StructureViewer(ap.getStructureSelectionManager()) - .viewStructures(ap, pr, ap.av.collateForPDB(pr)); - } - }); - } } } else @@ -1090,8 +1020,6 @@ public class PopupMenu extends JPopupMenu if (urlset != null) { int type = urlLink.getGroupURLType() & 3; - // System.out.println(urlLink.getGroupURLType() - // +" "+((String[])urlset[3])[0]); // first two bits ofurlLink type bitfield are sequenceids and sequences // TODO: FUTURE: ensure the groupURL menu structure can be generalised addshowLink(linkMenus[type], label @@ -1402,32 +1330,7 @@ public class PopupMenu extends JPopupMenu pdbFromFile_actionPerformed(); } }); - // RNAFold.setText("From RNA Fold with predict2D"); - // RNAFold.addActionListener(new ActionListener() - // { - // public void actionPerformed(ActionEvent e) - // { - // try { - // RNAFold_actionPerformed(); - // } catch (Exception e1) { - // // TODO Auto-generated catch block - // e1.printStackTrace(); - // } - // } - // }); - // ContraFold.setText("From Contra Fold with predict2D"); - // ContraFold.addActionListener(new ActionListener() - // { - // public void actionPerformed(ActionEvent e) - // { - // try { - // ContraFold_actionPerformed(); - // } catch (Exception e1) { - // // TODO Auto-generated catch block - // e1.printStackTrace(); - // } - // } - // }); + enterPDB.setText(MessageManager.getString("label.enter_pdb_id")); enterPDB.addActionListener(new ActionListener() { @@ -1476,7 +1379,22 @@ public class PopupMenu extends JPopupMenu } }); jMenu1.setText(MessageManager.getString("label.group")); - structureMenu.setText(MessageManager.getString("label.structure")); + structureMenu.setText(MessageManager.getString("label.view_structure")); + structureMenu.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent actionEvent) + { + SequenceI[] selectedSeqs = new SequenceI[] + { sequence }; + if (ap.av.getSelectionGroup() != null) + { + selectedSeqs = ap.av.getSequenceSelection(); + } + new StructureChooser(selectedSeqs, sequence, ap); + } + }); + viewStructureMenu.setText(MessageManager .getString("label.view_structure")); // colStructureMenu.setText("Colour By Structure"); @@ -1564,10 +1482,8 @@ public class PopupMenu extends JPopupMenu if (ap.getAlignment().isNucleotide()) { // JBPNote - commented since the colourscheme isn't functional - // colourMenu.add(RNAInteractionColour); colourMenu.add(purinePyrimidineColour); } - // colourMenu.add(covariationColour); colourMenu.add(userDefinedColour); if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null) @@ -1593,7 +1509,6 @@ public class PopupMenu extends JPopupMenu colourMenu.addSeparator(); colourMenu.add(abovePIDColour); colourMenu.add(conservationMenuItem); - // colourMenu.add(annotationMenuItem); editMenu.add(copy); editMenu.add(cut); editMenu.add(editSequence); @@ -1614,9 +1529,6 @@ public class PopupMenu extends JPopupMenu jMenu1.add(showColourText); jMenu1.add(outline); jMenu1.add(displayNonconserved); - structureMenu.add(pdbMenu); - structureMenu.add(viewStructureMenu); - // structureMenu.add(colStructureMenu); noColourmenuItem.setText(MessageManager.getString("label.none")); noColourmenuItem.addActionListener(new java.awt.event.ActionListener() { @@ -2548,18 +2460,7 @@ public class PopupMenu extends JPopupMenu } - // JBNote: commented out - these won't be instantiated here...! - // public void RNAFold_actionPerformed() throws Exception - // { - // Predict2D P2D = new Predict2D(); - // P2D.getStructure2DFromRNAFold("toto"); - // } - // - // public void ContraFold_actionPerformed() throws Exception - // { - // Predict2D P2D = new Predict2D(); - // P2D.getStructure2DFromContraFold("toto"); - // } + public void enterPDB_actionPerformed() { String id = JOptionPane.showInternalInputDialog(Desktop.desktop, diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index 06f4b0f..6a0c712 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -59,7 +59,42 @@ import com.stevesoft.pat.Regex; public class SequenceFetcher extends JPanel implements Runnable { - // ASequenceFetcher sfetch; + JLabel dbeg = new JLabel(); + + JDatabaseTree database; + + JButton databaseButt; + + 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(); + + BorderLayout borderLayout3 = new BorderLayout(); + JInternalFrame frame; IProgressIndicator guiWindow; @@ -80,6 +115,7 @@ public class SequenceFetcher extends JPanel implements Runnable private static Thread initingThread = null; + int debounceTrap = 0; /** * Blocking method that initialises and returns the shared instance of the * SequenceFetcher client @@ -154,9 +190,10 @@ public class SequenceFetcher extends JPanel implements Runnable return sfetch; } + private IProgressIndicator progressIndicator; public SequenceFetcher(IProgressIndicator guiIndic) { - final IProgressIndicator guiWindow = guiIndic; + this.progressIndicator = guiIndic; final SequenceFetcher us = this; // launch initialiser thread Thread sf = new Thread(new Runnable() @@ -165,9 +202,9 @@ public class SequenceFetcher extends JPanel implements Runnable @Override public void run() { - if (getSequenceFetcherSingleton(guiWindow) != null) + if (getSequenceFetcherSingleton(progressIndicator) != null) { - us.initGui(guiWindow); + us.initGui(progressIndicator); } else { @@ -318,37 +355,21 @@ public class SequenceFetcher extends JPanel implements Runnable databaseButt.setFont(JvSwingUtils.getLabelFont()); database.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { - try - { - 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()) - { - if (dbs instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource) - { - enablePunct = false; - break; - } - } - replacePunctuation.setEnabled(enablePunct); + debounceTrap++; + String currentSelection = database.getSelectedItem(); - } catch (Exception ex) + if (!currentSelection.equalsIgnoreCase("pdb")) + { + otherSourceAction(); + } + if (currentSelection.equalsIgnoreCase("pdb") && ((debounceTrap % 2) == 0)) { - dbeg.setText(""); - replacePunctuation.setEnabled(true); + pdbSourceAction(); } - jPanel2.repaint(); + } }); dbeg.setText(""); @@ -367,6 +388,44 @@ public class SequenceFetcher extends JPanel implements Runnable } + private void pdbSourceAction() + { + databaseButt.setText(database.getSelectedItem()); + new PDBSearchPanel(this); + frame.dispose(); + } + + private void otherSourceAction() + { + try + { + 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()) + { + if (dbs instanceof jalview.ws.dbsources.das.datamodel.DasSequenceSource) + { + enablePunct = false; + break; + } + } + replacePunctuation.setEnabled(enablePunct); + + } catch (Exception ex) + { + dbeg.setText(""); + replacePunctuation.setEnabled(true); + } + jPanel2.repaint(); + } + protected void example_actionPerformed() { DbSourceProxy db = null; @@ -385,41 +444,7 @@ public class SequenceFetcher extends JPanel implements Runnable jPanel3.repaint(); } - JLabel dbeg = new JLabel(); - - JDatabaseTree database; - - JButton databaseButt; - 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(); - - BorderLayout borderLayout3 = new BorderLayout(); public void close_actionPerformed(ActionEvent e) { @@ -861,4 +886,14 @@ public class SequenceFetcher extends JPanel implements Runnable } }); } + + public IProgressIndicator getProgressIndicator() + { + return progressIndicator; + } + + public void setProgressIndicator(IProgressIndicator progressIndicator) + { + this.progressIndicator = progressIndicator; + } } diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java new file mode 100644 index 0000000..3a54cc1 --- /dev/null +++ b/src/jalview/gui/StructureChooser.java @@ -0,0 +1,634 @@ +/* + + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) + * Copyright (C) 2014 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. + * + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +package jalview.gui; + +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.SequenceI; +import jalview.jbgui.GStructureChooser; +import jalview.jbgui.PDBDocFieldPreferences; +import jalview.util.MessageManager; +import jalview.ws.dbsources.PDBRestClient; +import jalview.ws.dbsources.PDBRestClient.PDBDocField; +import jalview.ws.uimodel.PDBRestRequest; +import jalview.ws.uimodel.PDBRestResponse; +import jalview.ws.uimodel.PDBRestResponse.PDBResponseSummary; + +import java.awt.event.ItemEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Vector; + +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; + +/** + * Provides the behaviors for the Structure chooser Panel + * + * @author tcnofoegbu + * + */ +@SuppressWarnings("serial") +public class StructureChooser extends GStructureChooser +{ + private boolean structuresDiscovered = false; + + private SequenceI selectedSequence; + + private SequenceI[] selectedSequences; + + private IProgressIndicator progressIndicator; + + private Collection discoveredStructuresSet; + + private PDBRestRequest lastPdbRequest; + + private PDBRestClient pdbRestCleint; + + private String selectedPdbFileName; + + private boolean isValidPBDEntry; + + public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq, + AlignmentPanel ap) + { + this.ap = ap; + this.selectedSequence = selectedSeq; + this.selectedSequences = selectedSeqs; + this.progressIndicator = (ap == null) ? null : ap.alignFrame; + init(); + } + + /** + * Initializes parameters used by the Structure Chooser Panel + */ + public void init() + { + Thread discoverPDBStructuresThread = new Thread(new Runnable() + { + @Override + public void run() + { + long startTime = System.currentTimeMillis(); + String msg = MessageManager.getString("status.fetching_db_refs"); + updateProgressIndicator(msg, startTime); + fetchStructuresMetaData(); + populateFilterComboBox(); + updateProgressIndicator(null, startTime); + mainFrame.setVisible(true); + updateCurrentView(); + } + }); + discoverPDBStructuresThread.start(); + } + + /** + * Updates the progress indicator with the specified message + * + * @param message + * displayed message for the operation + * @param id + * unique handle for this indicator + */ + public void updateProgressIndicator(String message, long id) + { + if (progressIndicator != null) + { + progressIndicator.setProgressBar(message, id); + } + } + + /** + * Retrieve meta-data for all the structure(s) for a given sequence(s) in a + * selection group + */ + public void fetchStructuresMetaData() + { + long startTime = System.currentTimeMillis(); + Collection wantedFields = PDBDocFieldPreferences + .getStructureSummaryFields(); + + discoveredStructuresSet = new LinkedHashSet(); + for (SequenceI seq : selectedSequences) + { + PDBRestRequest pdbRequest = new PDBRestRequest(); + pdbRequest.setAllowEmptySeq(false); + pdbRequest.setResponseSize(500); + pdbRequest.setFieldToSearchBy("(text:"); + pdbRequest.setWantedFields(wantedFields); + pdbRequest.setSearchTerm(buildQuery(seq) + ")"); + pdbRequest.setAssociatedSequence(seq.getName()); + pdbRestCleint = new PDBRestClient(); + PDBRestResponse resultList = pdbRestCleint.executeRequest(pdbRequest); + lastPdbRequest = pdbRequest; + if (resultList.getSearchSummary() != null + && !resultList.getSearchSummary().isEmpty()) + { + discoveredStructuresSet.addAll(resultList.getSearchSummary()); + updateSequenceDbRef(seq, resultList.getSearchSummary()); + } + } + + int noOfStructuresFound = 0; + if (discoveredStructuresSet != null + && !discoveredStructuresSet.isEmpty()) + { + tbl_summary.setModel(PDBRestResponse.getTableModel(lastPdbRequest, + discoveredStructuresSet)); + structuresDiscovered = true; + noOfStructuresFound = discoveredStructuresSet.size(); + } + String totalTime = (System.currentTimeMillis() - startTime) + + " milli secs"; + mainFrame.setTitle("Structure Chooser - " + noOfStructuresFound + + " Found (" + totalTime + ")"); + } + + /** + * Update the DBRef entry for a given sequence with values retrieved from + * PDBResponseSummary + * + * @param seq + * the Sequence to update its DBRef entry + * @param responseSummaries + * a collection of PDBResponseSummary + */ + public void updateSequenceDbRef(SequenceI seq, + Collection responseSummaries) + { + for (PDBResponseSummary response : responseSummaries) + { + PDBEntry newEntry = new PDBEntry(); + newEntry.setId(response.getPdbId()); + newEntry.setType("PDB"); + seq.getDatasetSequence().addPDBId(newEntry); + } + } + + /** + * Builds a query string for a given sequences using its DBRef entries + * + * @param seq + * the sequences to build a query for + * @return the built query string + */ + @SuppressWarnings("unchecked") + public static String buildQuery(SequenceI seq) + { + String query = seq.getName(); + StringBuilder queryBuilder = new StringBuilder(); + int count = 0; + + if (seq.getPDBId() != null) + { + for (PDBEntry entry : (Vector) seq.getPDBId()) + { + queryBuilder.append("text:").append(entry.getId()).append(" OR "); + } + } + + if (seq.getDBRef() != null && seq.getDBRef().length != 0) + { + for (DBRefEntry dbRef : seq.getDBRef()) + { + queryBuilder.append("text:") + .append(dbRef.getAccessionId().replaceAll("GO:", "")) + .append(" OR "); + ++count; + if (count > 10) + { + break; + } + } + int endIndex = queryBuilder.lastIndexOf(" OR "); + query = queryBuilder.toString().substring(5, endIndex); + } + return query; + } + + /** + * Filters a given list of discovered structures based on supplied argument + * + * @param fieldToFilterBy + * the field to filter by + */ + public void filterResultSet(final String fieldToFilterBy) + { + Thread filterThread = new Thread(new Runnable() + { + @Override + public void run() + { + long startTime = System.currentTimeMillis(); + try + { + lbl_loading.setVisible(true); + + Collection wantedFields = PDBDocFieldPreferences + .getStructureSummaryFields(); + Collection filteredResponse = new HashSet(); + for (SequenceI seq : selectedSequences) + { + PDBRestRequest pdbRequest = new PDBRestRequest(); + pdbRequest.setAllowEmptySeq(false); + pdbRequest.setResponseSize(1); + pdbRequest.setFieldToSearchBy("(text:"); + pdbRequest.setFieldToSortBy(fieldToFilterBy, + !chk_invertFilter.isSelected()); + pdbRequest.setSearchTerm(buildQuery(seq) + ")"); + pdbRequest.setWantedFields(wantedFields); + pdbRequest.setAssociatedSequence(seq.getName()); + pdbRestCleint = new PDBRestClient(); + PDBRestResponse resultList = pdbRestCleint + .executeRequest(pdbRequest); + lastPdbRequest = pdbRequest; + if (resultList.getSearchSummary() != null + && !resultList.getSearchSummary().isEmpty()) + { + filteredResponse.addAll(resultList.getSearchSummary()); + } + } + + if (!filteredResponse.isEmpty()) + { + final int filterResponseCount = filteredResponse.size(); + Collection reorderedStructuresSet = new LinkedHashSet(); + reorderedStructuresSet.addAll(filteredResponse); + reorderedStructuresSet.addAll(discoveredStructuresSet); + tbl_summary.setModel(PDBRestResponse.getTableModel( + lastPdbRequest, reorderedStructuresSet)); + + // Update table selection model here + tbl_summary.addRowSelectionInterval(0, filterResponseCount - 1); + + } + + lbl_loading.setVisible(false); + String totalTime = (System.currentTimeMillis() - startTime) + + " milli secs"; + mainFrame.setTitle("Structure Chooser - Filter time (" + + totalTime + ")"); + + validateSelections(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + }); + filterThread.start(); + } + + + /** + * Handles action event for btn_pdbFromFile + */ + public void pdbFromFile_actionPerformed() + { + jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser( + jalview.bin.Cache.getProperty("LAST_DIRECTORY")); + chooser.setFileView(new jalview.io.JalviewFileView()); + chooser.setDialogTitle(MessageManager.formatMessage( + "label.select_pdb_file_for", new String[] + { selectedSequence.getDisplayId(false) })); + chooser.setToolTipText(MessageManager.formatMessage( + "label.load_pdb_file_associate_with_sequence", new String[] + { selectedSequence.getDisplayId(false) })); + + int value = chooser.showOpenDialog(null); + if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION) + { + selectedPdbFileName = chooser.getSelectedFile().getPath(); + jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName); + validateSelections(); + } + } + + /** + * Populates the filter combo-box options dynamically depending on discovered + * structures + */ + protected void populateFilterComboBox() + { + if (isStructuresDiscovered()) + { + cmb_filterOption.addItem(new FilterOption("Best Quality", + PDBDocField.OVERALL_QUALITY.getCode(), VIEWS_FILTER)); + cmb_filterOption.addItem(new FilterOption("Best UniProt Coverage", + PDBDocField.UNIPROT_COVERAGE.getCode(), VIEWS_FILTER)); + cmb_filterOption.addItem(new FilterOption("Highest Resolution", + PDBDocField.RESOLUTION.getCode(), VIEWS_FILTER)); + cmb_filterOption.addItem(new FilterOption("Highest Protein Chain", + PDBDocField.PROTEIN_CHAIN_COUNT.getCode(), VIEWS_FILTER)); + cmb_filterOption.addItem(new FilterOption("Highest Bound Molecules", + PDBDocField.BOUND_MOLECULE_COUNT.getCode(), VIEWS_FILTER)); + cmb_filterOption.addItem(new FilterOption("Highest Polymer Residues", + PDBDocField.POLYMER_RESIDUE_COUNT.getCode(), VIEWS_FILTER)); + } + cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-", + VIEWS_ENTER_ID)); + cmb_filterOption.addItem(new FilterOption("From File", "-", + VIEWS_FROM_FILE)); + } + + /** + * Updates the displayed view based on the selected filter option + */ + protected void updateCurrentView() + { + FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption + .getSelectedItem()); + layout_switchableViews.show(pnl_switchableViews, + selectedFilterOpt.getView()); + String filterTitle = mainFrame.getTitle(); + mainFrame.setTitle(frameTitle); + chk_invertFilter.setVisible(false); + if (selectedFilterOpt.getView() == VIEWS_FILTER) + { + mainFrame.setTitle(filterTitle); + chk_invertFilter.setVisible(true); + filterResultSet(selectedFilterOpt.getValue()); + } + else + { + idInputAssSeqPanel.loadCmbAssSeq(); + fileChooserAssSeqPanel.loadCmbAssSeq(); + } + validateSelections(); + } + + /** + * Validates user selection and activates the view button if all parameters + * are correct + */ + public void validateSelections() + { + FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption + .getSelectedItem()); + btn_view.setEnabled(false); + String currentView = selectedFilterOpt.getView(); + if (currentView == VIEWS_FILTER) + { + if (tbl_summary.getSelectedRows().length > 0) + { + btn_view.setEnabled(true); + } + } + else if (currentView == VIEWS_ENTER_ID) + { + validateAssociationEnterPdb(); + } + else if (currentView == VIEWS_FROM_FILE) + { + validateAssociationFromFile(); + } + } + + /** + * Validates inputs from the Manual PDB entry panel + */ + public void validateAssociationEnterPdb() + { + AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel + .getCmb_assSeq().getSelectedItem(); + lbl_pdbManualFetchStatus.setIcon(errorImage); + if (selectedSequences.length == 1 + || !assSeqOpt.getName().equalsIgnoreCase( + "-Select Associated Seq-")) + { + txt_search.setEnabled(true); + if (isValidPBDEntry) + { + btn_view.setEnabled(true); + lbl_pdbManualFetchStatus.setIcon(goodImage); + } + } + else + { + txt_search.setEnabled(false); + lbl_pdbManualFetchStatus.setIcon(errorImage); + } + } + + /** + * Validates inputs for the manual PDB file selection options + */ + public void validateAssociationFromFile() + { + AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel + .getCmb_assSeq().getSelectedItem(); + lbl_fromFileStatus.setIcon(errorImage); + if (selectedSequences.length == 1 + || (assSeqOpt != null + && !assSeqOpt.getName().equalsIgnoreCase( + "-Select Associated Seq-"))) + { + btn_pdbFromFile.setEnabled(true); + if (selectedPdbFileName != null && selectedPdbFileName.length() > 0) + { + btn_view.setEnabled(true); + lbl_fromFileStatus.setIcon(goodImage); + } + } + else + { + btn_pdbFromFile.setEnabled(false); + lbl_fromFileStatus.setIcon(errorImage); + } + } + + @Override + public void cmbAssSeqStateChanged() + { + validateSelections(); + } + + /** + * Handles the state change event for the 'filter' combo-box and 'invert' + * check-box + */ + @Override + protected void stateChanged(ItemEvent e) + { + if (e.getSource() instanceof JCheckBox) + { + updateCurrentView(); + } + else + { + if (e.getStateChange() == ItemEvent.SELECTED) + { + updateCurrentView(); + } + } + + } + + /** + * Handles action event for btn_ok + */ + @Override + public void ok_ActionPerformed() + { + FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption + .getSelectedItem()); + String currentView = selectedFilterOpt.getView(); + if (currentView == VIEWS_FILTER) + { + int pdbIdCol = PDBRestClient.getPDBIdColumIndex( + lastPdbRequest.getWantedFields(), true); + int[] selectedRows = tbl_summary.getSelectedRows(); + PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length]; + int count = 0; + for (int summaryRow : selectedRows) + { + String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol) + .toString(); + PDBEntry pdbEntry = new PDBEntry(); + pdbEntry.setId(pdbIdStr); + pdbEntry.setType("PDB"); + pdbEntriesToView[count++] = pdbEntry; + } + new StructureViewer(ap.getStructureSelectionManager()) + .viewStructures(ap, pdbEntriesToView, + ap.av.collateForPDB(pdbEntriesToView)); + } + else if (currentView == VIEWS_ENTER_ID) + { + selectedSequence = ((AssociateSeqOptions) idInputAssSeqPanel + .getCmb_assSeq().getSelectedItem()).getSequence(); + PDBEntry pdbEntry = new PDBEntry(); + pdbEntry.setId(txt_search.getText()); + pdbEntry.setType("PDB"); + selectedSequence.getDatasetSequence().addPDBId(pdbEntry); + PDBEntry[] pdbEntriesToView = new PDBEntry[] + { pdbEntry }; + new StructureViewer(ap.getStructureSelectionManager()) + .viewStructures(ap, pdbEntriesToView, + ap.av.collateForPDB(pdbEntriesToView)); + } + else if (currentView == VIEWS_FROM_FILE) + { + selectedSequence = ((AssociateSeqOptions) fileChooserAssSeqPanel + .getCmb_assSeq().getSelectedItem()).getSequence(); + new AssociatePdbFileWithSeq().associatePdbWithSeq( + selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE, + selectedSequence, true, Desktop.instance); + } + mainFrame.dispose(); + } + + /** + * Populates the combo-box used in associating manually fetched structures to + * a unique sequence when more than one sequence selection is made. + */ + public void populateCmbAssociateSeqOptions( + JComboBox cmb_assSeq, JLabel lbl_associateSeq) + { + cmb_assSeq.removeAllItems(); + cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-", + null)); + // cmb_assSeq.addItem(new AssociateSeqOptions("Auto Detect", null)); + lbl_associateSeq.setVisible(false); + if (selectedSequences.length > 1) + { + for (SequenceI seq : selectedSequences) + { + cmb_assSeq.addItem(new AssociateSeqOptions(seq)); + } + } + else + { + String seqName = selectedSequence.getDisplayId(false); + seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39); + lbl_associateSeq.setText(seqName); + lbl_associateSeq.setVisible(true); + cmb_assSeq.setVisible(false); + } + } + + public boolean isStructuresDiscovered() + { + return structuresDiscovered; + } + + public void setStructuresDiscovered(boolean structuresDiscovered) + { + this.structuresDiscovered = structuresDiscovered; + } + + public Collection getDiscoveredStructuresSet() + { + return discoveredStructuresSet; + } + + @Override + protected void txt_search_ActionPerformed() + { + isValidPBDEntry = false; + if (txt_search.getText().length() > 0) + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.PDB_ID); + PDBRestRequest pdbRequest = new PDBRestRequest(); + pdbRequest.setAllowEmptySeq(false); + pdbRequest.setResponseSize(1); + pdbRequest.setFieldToSearchBy("(pdb_id:"); + pdbRequest.setWantedFields(wantedFields); + pdbRequest.setSearchTerm(txt_search.getText() + ")"); + pdbRequest.setAssociatedSequence(selectedSequence.getName()); + pdbRestCleint = new PDBRestClient(); + PDBRestResponse resultList = pdbRestCleint.executeRequest(pdbRequest); + if (resultList.getSearchSummary() != null + && resultList.getSearchSummary().size() > 0) + { + isValidPBDEntry = true; + } + } + validateSelections(); + } + + @Override + public void tabRefresh() + { + if (selectedSequences != null) + { + Thread refreshThread = new Thread(new Runnable() + { + @Override + public void run() + { + fetchStructuresMetaData(); + filterResultSet(((FilterOption) cmb_filterOption + .getSelectedItem()).getValue()); + } + }); + refreshThread.start(); + } + } + +} diff --git a/src/jalview/jbgui/GPDBSearchPanel.java b/src/jalview/jbgui/GPDBSearchPanel.java new file mode 100644 index 0000000..29a0014 --- /dev/null +++ b/src/jalview/jbgui/GPDBSearchPanel.java @@ -0,0 +1,242 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) + * Copyright (C) 2014 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. + * + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +package jalview.jbgui; + +import jalview.gui.Desktop; +import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource; +import jalview.util.MessageManager; +import jalview.ws.dbsources.PDBRestClient.PDBDocField; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +/** + * GUI layout for PDB Fetch Panel + * + * @author tcnofoegbu + * + */ +@SuppressWarnings("serial") +public abstract class GPDBSearchPanel extends JPanel +{ + protected String frameTitle = MessageManager + .getString("label.pdb_sequence_getcher"); + + protected JInternalFrame mainFrame = new JInternalFrame(frameTitle); + + protected JComboBox cmb_searchTarget = new JComboBox(); + + protected JButton btn_ok = new JButton(); + + protected JButton btn_back = new JButton(); + + protected JButton btn_cancel = new JButton(); + + protected JTextField txt_search = new JTextField(20); + + protected JTable tbl_summary = new JTable(); + + protected JScrollPane scrl_searchResult = new JScrollPane( +tbl_summary); + + private JTabbedPane tabbedPane = new JTabbedPane(); + + private PDBDocFieldPreferences pdbDocFieldPrefs = new PDBDocFieldPreferences( + PreferenceSource.SEARCH_SUMMARY); + + private JPanel pnl_actions = new JPanel(); + + private JPanel pnl_results = new JPanel(); + + private JPanel pnl_inputs = new JPanel(); + + private BorderLayout mainLayout = new BorderLayout(); + + public GPDBSearchPanel() + { + try + { + jbInit(); + mainFrame.invalidate(); + mainFrame.pack(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * Initializes the GUI default properties + * + * @throws Exception + */ + private void jbInit() throws Exception + { + tbl_summary.setAutoCreateRowSorter(true); + btn_back.setFont(new java.awt.Font("Verdana", 0, 12)); + btn_back.setText(MessageManager.getString("action.back")); + btn_back.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + btn_back_ActionPerformed(); + } + }); + btn_ok.setFont(new java.awt.Font("Verdana", 0, 12)); + btn_ok.setText(MessageManager.getString("action.ok")); + btn_ok.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + btn_ok_ActionPerformed(); + } + }); + btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12)); + btn_cancel.setText(MessageManager.getString("action.cancel")); + btn_cancel.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + btn_cancel_ActionPerformed(); + } + }); + + scrl_searchResult.setPreferredSize(new Dimension(500, 300)); + scrl_searchResult + .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12)); + cmb_searchTarget.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + txt_search_ActionPerformed(); + } + }); + + populateCmbSearchTargetOptions(); + + txt_search.setFont(new java.awt.Font("Verdana", 0, 12)); + txt_search.getDocument().addDocumentListener(new DocumentListener() + { + @Override + public void insertUpdate(DocumentEvent e) + { + txt_search_ActionPerformed(); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + txt_search_ActionPerformed(); + } + + @Override + public void changedUpdate(DocumentEvent e) + { + txt_search_ActionPerformed(); + } + }); + + final String searchTabTitle = MessageManager + .getString("label.search_result"); + ChangeListener changeListener = new ChangeListener() + { + public void stateChanged(ChangeEvent changeEvent) + { + JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent + .getSource(); + int index = sourceTabbedPane.getSelectedIndex(); + if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle)) + { + txt_search_ActionPerformed(); + } + } + }; + tabbedPane.addChangeListener(changeListener); + tabbedPane.setPreferredSize(new Dimension(500, 300)); + tabbedPane.add(searchTabTitle, scrl_searchResult); + tabbedPane.add( + MessageManager.getString("label.configure_displayed_columns"), + pdbDocFieldPrefs); + + pnl_actions.add(btn_back); + pnl_actions.add(btn_ok); + pnl_actions.add(btn_cancel); + + pnl_results.add(tabbedPane); + pnl_inputs.add(cmb_searchTarget); + pnl_inputs.add(txt_search); + + this.setLayout(mainLayout); + this.add(pnl_inputs, java.awt.BorderLayout.NORTH); + this.add(pnl_results, java.awt.BorderLayout.CENTER); + this.add(pnl_actions, java.awt.BorderLayout.SOUTH); + mainFrame.setVisible(true); + mainFrame.setContentPane(this); + mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400); + } + + public JComboBox getCmbSearchTarget() + { + return cmb_searchTarget; + } + + public JTextField getTxtSearch() + { + return txt_search; + } + + public JInternalFrame getMainFrame() + { + return mainFrame; + } + + public abstract void txt_search_ActionPerformed(); + + public abstract void btn_ok_ActionPerformed(); + + public abstract void btn_back_ActionPerformed(); + + public abstract void btn_cancel_ActionPerformed(); + + public abstract void populateCmbSearchTargetOptions(); + +} diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java index bec4cdb..1d35477 100755 --- a/src/jalview/jbgui/GPreferences.java +++ b/src/jalview/jbgui/GPreferences.java @@ -22,6 +22,7 @@ package jalview.jbgui; import jalview.gui.JvSwingUtils; import jalview.gui.StructureViewer.ViewerType; +import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource; import jalview.util.MessageManager; import java.awt.BorderLayout; @@ -149,6 +150,7 @@ public class GPreferences extends JPanel protected JTextField chimeraPath = new JTextField(); + /* * Colours tab components */ @@ -745,8 +747,8 @@ public class GPreferences extends JPanel .getString("label.structure_options"))); structureTab.setLayout(null); final int width = 400; - final int height = 23; - final int lineSpacing = 30; + final int height = 22; + final int lineSpacing = 25; int ypos = 30; structFromPdb.setFont(verdana11); @@ -840,9 +842,23 @@ public class GPreferences extends JPanel }); structureTab.add(chimeraPath); + ypos += lineSpacing; + // scrl_pdbDocFieldConfig.setPreferredSize(new Dimension(450, 100)); + // scrl_pdbDocFieldConfig + // .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + // scrl_pdbDocFieldConfig.setBounds(); + PDBDocFieldPreferences docFieldPref = new PDBDocFieldPreferences( + PreferenceSource.PREFERENCES); + docFieldPref.setBounds(new Rectangle(10, ypos + 5, 450, 120)); + structureTab.add(docFieldPref); + + + + return structureTab; } + /** * Action on choosing a structure viewer from combobox options. * diff --git a/src/jalview/jbgui/GStructureChooser.java b/src/jalview/jbgui/GStructureChooser.java new file mode 100644 index 0000000..b79a7f7 --- /dev/null +++ b/src/jalview/jbgui/GStructureChooser.java @@ -0,0 +1,487 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) + * Copyright (C) 2014 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. + * + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +package jalview.jbgui; + +import jalview.datamodel.SequenceI; +import jalview.gui.AlignmentPanel; +import jalview.gui.Desktop; +import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource; +import jalview.util.MessageManager; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +@SuppressWarnings("serial") +/** + * GUI layout for structure chooser + * @author tcnofoegbu + * + */ +public abstract class GStructureChooser extends JPanel implements + ItemListener +{ + protected String frameTitle = MessageManager + .getString("label.structure_chooser"); + + protected JInternalFrame mainFrame = new JInternalFrame(frameTitle); + + protected JComboBox cmb_filterOption = new JComboBox(); + + protected AlignmentPanel ap; + + protected JLabel lbl_result = new JLabel( + MessageManager.getString("label.select")); + + protected JButton btn_view = new JButton(); + + protected JButton btn_cancel = new JButton(); + + protected JButton btn_pdbFromFile = new JButton(); + + protected JTextField txt_search = new JTextField(14); + + private JPanel pnl_actions = new JPanel(); + + private JPanel pnl_filter = new JPanel(); + + private JPanel pnl_idInput = new JPanel(new FlowLayout()); + + private JPanel pnl_fileChooser = new JPanel(new FlowLayout()); + + private JPanel pnl_idInputBL = new JPanel(new BorderLayout()); + + private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout()); + + protected JPanel pnl_switchableViews = new JPanel(new CardLayout()); + + protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews + .getLayout()); + + private BorderLayout mainLayout = new BorderLayout(); + + protected JCheckBox chk_rememberSettings = new JCheckBox( + MessageManager.getString("label.dont_ask_me_again")); + + protected JCheckBox chk_invertFilter = new JCheckBox( + MessageManager.getString("label.invert")); + + protected ImageIcon loadingImage = new ImageIcon(getClass().getResource( + "/images/loading.gif")); + + protected ImageIcon goodImage = new ImageIcon(getClass().getResource( + "/images/good.png")); + + protected ImageIcon errorImage = new ImageIcon(getClass().getResource( + "/images/error.png")); + + protected JLabel lbl_loading = new JLabel(loadingImage); + + protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage); + + protected JLabel lbl_fromFileStatus = new JLabel(errorImage); + + + protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel(); + + protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel(); + + protected static final String VIEWS_FILTER = "VIEWS_FILTER"; + + protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE"; + + protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID"; + + protected JTable tbl_summary = new JTable(); + + protected JScrollPane scrl_foundStructures = new JScrollPane( + tbl_summary); + + private JTabbedPane tabbedPane = new JTabbedPane(); + + private PDBDocFieldPreferences pdbDocFieldPrefs = new PDBDocFieldPreferences( + PreferenceSource.STRUCTURE_CHOOSER); + + public GStructureChooser() + { + try + { + jbInit(); + mainFrame.setVisible(false); + mainFrame.invalidate(); + mainFrame.pack(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * Initializes the GUI default properties + * + * @throws Exception + */ + private void jbInit() throws Exception + { + tbl_summary.setAutoCreateRowSorter(true); + btn_view.setFont(new java.awt.Font("Verdana", 0, 12)); + btn_view.setText(MessageManager.getString("action.view")); + btn_view.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + ok_ActionPerformed(); + } + }); + btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12)); + btn_cancel.setText(MessageManager.getString("action.cancel")); + btn_cancel.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + mainFrame.dispose(); + } + }); + + btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12)); + String btn_title = MessageManager.getString("label.select_pdb_file"); + btn_pdbFromFile.setText(btn_title + " "); + btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + pdbFromFile_actionPerformed(); + } + }); + + scrl_foundStructures.setPreferredSize(new Dimension(500, 300)); + scrl_foundStructures + .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12)); + chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12)); + chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12)); + + + txt_search.setToolTipText(MessageManager + .getString("label.enter_pdb_id")); + cmb_filterOption.setToolTipText(MessageManager + .getString("info.select_filter_option")); + txt_search.getDocument().addDocumentListener(new DocumentListener() + { + @Override + public void insertUpdate(DocumentEvent e) + { + txt_search_ActionPerformed(); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + txt_search_ActionPerformed(); + } + + @Override + public void changedUpdate(DocumentEvent e) + { + txt_search_ActionPerformed(); + } + }); + + cmb_filterOption.addItemListener(this); + chk_invertFilter.addItemListener(this); + + pnl_actions.add(chk_rememberSettings); + pnl_actions.add(btn_view); + pnl_actions.add(btn_cancel); + + // pnl_filter.add(lbl_result); + pnl_filter.add(cmb_filterOption); + pnl_filter.add(lbl_loading); + pnl_filter.add(chk_invertFilter); + lbl_loading.setVisible(false); + + pnl_idInput.add(txt_search); + pnl_idInput.add(lbl_pdbManualFetchStatus); + + pnl_fileChooser.add(btn_pdbFromFile); + pnl_fileChooser.add(lbl_fromFileStatus); + + pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH); + pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER); + + pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH); + pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER); + + final String foundStructureSummary = MessageManager + .getString("label.found_structures_summary"); + + ChangeListener changeListener = new ChangeListener() + { + public void stateChanged(ChangeEvent changeEvent) + { + JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent + .getSource(); + int index = sourceTabbedPane.getSelectedIndex(); + if (sourceTabbedPane.getTitleAt(index) + .equals(foundStructureSummary)) + { + tabRefresh(); + } + } + }; + tabbedPane.addChangeListener(changeListener); + tabbedPane.setPreferredSize(new Dimension(500, 300)); + tabbedPane.add(foundStructureSummary, scrl_foundStructures); + tabbedPane.add( + MessageManager.getString("label.configure_displayed_columns"), + pdbDocFieldPrefs); + + + pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE); + pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID); + pnl_switchableViews.add(tabbedPane, VIEWS_FILTER); + + this.setLayout(mainLayout); + this.add(pnl_filter, java.awt.BorderLayout.NORTH); + this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER); + this.add(pnl_actions, java.awt.BorderLayout.SOUTH); + + mainFrame.setVisible(true); + mainFrame.setContentPane(this); + mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400); + } + + + @Override + /** + * Event listener for the 'filter' combo-box and 'invert' check-box + */ + public void itemStateChanged(ItemEvent e) + { + stateChanged(e); + } + + /** + * This inner class provides the data model for the structure filter combo-box + * + * @author tcnofoegbu + * + */ + public class FilterOption + { + private String name; + + private String value; + + private String view; + + public FilterOption(String name, String value, String view) + { + this.name = name; + this.value = value; + this.view = view; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getValue() + { + return value; + } + + public void setValue(String value) + { + this.value = value; + } + + public String getView() + { + return view; + } + + public void setView(String view) + { + this.view = view; + } + + public String toString() + { + return this.name; + } + } + + /** + * This inner class provides the provides the data model for associate + * sequence combo-box - cmb_assSeq + * + * @author tcnofoegbu + * + */ + public class AssociateSeqOptions + { + private SequenceI sequence; + private String name; + + public AssociateSeqOptions(SequenceI seq) + { + this.sequence = seq; + this.name = (seq.getName().length() >= 23) ? seq.getName().substring( + 0, 23) : seq.getName(); + } + + public AssociateSeqOptions(String name, SequenceI seq) + { + this.name = name; + this.sequence = seq; + } + + public String toString() + { + return name; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public SequenceI getSequence() + { + return sequence; + } + + public void setSequence(SequenceI sequence) + { + this.sequence = sequence; + } + + } + + /** + * This inner class holds the Layout and configuration of the panel which + * handles association of manually fetched structures to a unique sequence + * when more than one sequence selection is made + * + * @author tcnofoegbu + * + */ + public class AssciateSeqPanel extends JPanel implements ItemListener + { + private JComboBox cmb_assSeq = new JComboBox(); + + private JLabel lbl_associateSeq = new JLabel(); + + public AssciateSeqPanel() + { + this.setLayout(new FlowLayout()); + this.add(cmb_assSeq); + this.add(lbl_associateSeq); + cmb_assSeq.setToolTipText(MessageManager + .getString("info.associate_wit_sequence")); + cmb_assSeq.addItemListener(this); + } + + public void loadCmbAssSeq() + { + populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq); + } + + public JComboBox getCmb_assSeq() + { + return cmb_assSeq; + } + + public void setCmb_assSeq(JComboBox cmb_assSeq) + { + this.cmb_assSeq = cmb_assSeq; + } + + @Override + public void itemStateChanged(ItemEvent e) + { + if (e.getStateChange() == ItemEvent.SELECTED) + { + cmbAssSeqStateChanged(); + } + } + } + + public JComboBox getCmbFilterOption() + { + return cmb_filterOption; + } + + protected abstract void stateChanged(ItemEvent e); + + protected abstract void updateCurrentView(); + + protected abstract void populateFilterComboBox(); + + protected abstract void ok_ActionPerformed(); + + protected abstract void pdbFromFile_actionPerformed(); + + protected abstract void txt_search_ActionPerformed(); + + public abstract void populateCmbAssociateSeqOptions( + JComboBox cmb_assSeq, JLabel lbl_associateSeq); + + public abstract void cmbAssSeqStateChanged(); + + public abstract void tabRefresh(); +} diff --git a/src/jalview/jbgui/PDBDocFieldPreferences.java b/src/jalview/jbgui/PDBDocFieldPreferences.java new file mode 100644 index 0000000..2021d0b --- /dev/null +++ b/src/jalview/jbgui/PDBDocFieldPreferences.java @@ -0,0 +1,228 @@ +package jalview.jbgui; + +import jalview.ws.dbsources.PDBRestClient.PDBDocField; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; + +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +@SuppressWarnings("serial") +public class PDBDocFieldPreferences extends JScrollPane +{ + protected JTable tbl_pdbDocFieldConfig = new JTable(); + + protected JScrollPane scrl_pdbDocFieldConfig = new JScrollPane( + tbl_pdbDocFieldConfig); + + private HashMap map = new HashMap(); + + private static Collection searchSummaryFields = new HashSet(); + + private static Collection structureSummaryFields = new HashSet(); + + public enum PreferenceSource + { + SEARCH_SUMMARY, STRUCTURE_CHOOSER, PREFERENCES; + } + + private PreferenceSource currentSource; + + static + { + searchSummaryFields.add(PDBDocField.PDB_ID); + searchSummaryFields.add(PDBDocField.TITLE); + + structureSummaryFields.add(PDBDocField.PDB_ID); + structureSummaryFields.add(PDBDocField.TITLE); + } + + public PDBDocFieldPreferences(PreferenceSource source) + { + tbl_pdbDocFieldConfig.setAutoCreateRowSorter(true); + this.getViewport().add(tbl_pdbDocFieldConfig); + this.currentSource = source; + + String[] columnNames = null; + switch (source) + { + case SEARCH_SUMMARY: + columnNames = new String[] + { "PDB Feild", "Show in search summary" }; + break; + case STRUCTURE_CHOOSER: + columnNames = new String[] + { "PDB Feild", "Show in structure summary" }; + break; + case PREFERENCES: + columnNames = new String[] + { "PDB Feild", "Show in search summary", "Show in structure summary" }; + break; + default: + break; + } + + Object[][] data = new Object[PDBDocField.values().length - 1][3]; + int x = 0; + for (PDBDocField field : PDBDocField.values()) + { + if (field.getName().equalsIgnoreCase("all")) + { + continue; + } + + switch (source) + { + case SEARCH_SUMMARY: + data[x++] = new Object[] + { field.getName(), searchSummaryFields.contains(field) }; + break; + case STRUCTURE_CHOOSER: + data[x++] = new Object[] + { field.getName(), structureSummaryFields.contains(field) }; + break; + case PREFERENCES: + data[x++] = new Object[] + { field.getName(), searchSummaryFields.contains(field), + structureSummaryFields.contains(field) }; + break; + default: + break; + } + map.put(field.getName(), field); + } + + PDBFieldTableModel model = new PDBFieldTableModel(columnNames, data); + tbl_pdbDocFieldConfig.setModel(model); + } + + public static Collection getSearchSummaryFields() + { + return searchSummaryFields; + } + + public static void setSearchSummaryFields( + Collection searchSummaryFields) + { + PDBDocFieldPreferences.searchSummaryFields = searchSummaryFields; + } + + public static Collection getStructureSummaryFields() + { + return structureSummaryFields; + } + + public static void setStructureSummaryFields( + Collection structureSummaryFields) + { + PDBDocFieldPreferences.structureSummaryFields = structureSummaryFields; + } + + class PDBFieldTableModel extends AbstractTableModel + { + + public PDBFieldTableModel(String[] columnNames, Object[][] data) + { + this.data = data; + this.columnNames = columnNames; + } + + private Object[][] data; + + private String[] columnNames; + + public int getColumnCount() + { + return columnNames.length; + } + + public int getRowCount() + { + return data.length; + } + + public String getColumnName(int col) + { + return columnNames[col]; + } + + public Object getValueAt(int row, int col) + { + return data[row][col]; + } + + /* + * JTable uses this method to determine the default renderer/ editor for + * each cell. If we didn't implement this method, then the last column would + * contain text ("true"/"false"), rather than a check box. + */ + public Class getColumnClass(int c) + { + return getValueAt(0, c).getClass(); + } + + /* + * Don't need to implement this method unless your table's editable. + */ + public boolean isCellEditable(int row, int col) + { + // Note that the data/cell address is constant, + // no matter where the cell appears onscreen. + return col == 1 || col == 2; + + } + + /* + * Don't need to implement this method unless your table's data can change. + */ + public void setValueAt(Object value, int row, int col) + { + data[row][col] = value; + fireTableCellUpdated(row, col); + + String name = getValueAt(row, 0).toString(); + boolean selected = ((Boolean) value).booleanValue(); + + PDBDocField pdbField = map.get(name); + + if (currentSource == PreferenceSource.SEARCH_SUMMARY) + { + updatePrefs(searchSummaryFields, pdbField, selected); + } + else if (currentSource == PreferenceSource.STRUCTURE_CHOOSER) + { + updatePrefs(structureSummaryFields, pdbField, selected); + } + else if (currentSource == PreferenceSource.PREFERENCES) + { + if (col == 1) + { + updatePrefs(searchSummaryFields, pdbField, selected); + } + else if (col == 2) + { + updatePrefs(structureSummaryFields, pdbField, selected); + } + } + } + + private void updatePrefs(Collection prefConfig, + PDBDocField pdbField, + boolean selected) + { + if (prefConfig.contains(pdbField) && !selected) + { + prefConfig.remove(pdbField); + } + + if (!prefConfig.contains(pdbField) && selected) + { + prefConfig.add(pdbField); + } + } + + } +} diff --git a/src/jalview/util/Format.java b/src/jalview/util/Format.java index 369d766..d14e4ad 100755 --- a/src/jalview/util/Format.java +++ b/src/jalview/util/Format.java @@ -625,7 +625,7 @@ public class Format /** * Formats a character into a string (like sprintf in C) * - * @param x + * @param debounceTrap * the value to format * @return the formatted string */ @@ -644,7 +644,7 @@ public class Format /** * Formats a string into a larger string (like sprintf in C) * - * @param x + * @param debounceTrap * the value to format * @return the formatted string */ diff --git a/src/jalview/util/MessageManager.java b/src/jalview/util/MessageManager.java index a92b29a..4001cb2 100644 --- a/src/jalview/util/MessageManager.java +++ b/src/jalview/util/MessageManager.java @@ -92,6 +92,11 @@ public class MessageManager public static String formatMessage(String key, Object... params) { + return MessageFormat.format(rb.getString(key), params); + } + + public static String formatMessage(String key, String[] params) + { return MessageFormat.format(rb.getString(key), (Object[]) params); } diff --git a/src/jalview/ws/dbsources/PDBRestClient.java b/src/jalview/ws/dbsources/PDBRestClient.java new file mode 100644 index 0000000..1ab6125 --- /dev/null +++ b/src/jalview/ws/dbsources/PDBRestClient.java @@ -0,0 +1,338 @@ +package jalview.ws.dbsources; + +import jalview.ws.uimodel.PDBRestRequest; +import jalview.ws.uimodel.PDBRestResponse; +import jalview.ws.uimodel.PDBRestResponse.PDBResponseSummary; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import javax.ws.rs.core.MediaType; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.json.JSONConfiguration; + +/** + * A rest client for querying the Search endpoing of the PDB REST API + * + * @author tcnofoegbu + * + */ +public class PDBRestClient +{ + private static String PDB_SEARCH_ENDPOINT = "http://wwwdev.ebi.ac.uk/pdbe/search/pdb/select?"; + + private static int DEFAULT_RESPONSE_SIZE = 200; + + /** + * Takes a PDBRestRequest object and returns a response upon execution + * + * @param pdbRestRequest + * the PDBRestRequest instance to be processed + * @return the pdbResponse object for the given request + */ + public PDBRestResponse executeRequest(PDBRestRequest pdbRestRequest) + { + ClientConfig clientConfig = new DefaultClientConfig(); + clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, + Boolean.TRUE); + Client client = Client.create(clientConfig); + + String wantedFields = getPDBDocFieldsAsCommaDelimitedString(pdbRestRequest + .getWantedFields()); + int responseSize = (pdbRestRequest.getResponseSize() == 0) ? DEFAULT_RESPONSE_SIZE + : pdbRestRequest.getResponseSize(); + String sortParam = (pdbRestRequest.getFieldToSortBy() == null || pdbRestRequest + .getFieldToSortBy().trim().isEmpty()) ? "" : (pdbRestRequest + .getFieldToSortBy() + (pdbRestRequest.isAscending() ? " asc" + : " desc")); + + // Build request parameters for the REST Request + WebResource webResource = client.resource(PDB_SEARCH_ENDPOINT) + .queryParam("wt", "json").queryParam("fl", wantedFields) + .queryParam("rows", String.valueOf(responseSize)) + .queryParam("q", pdbRestRequest.getQuery()) + .queryParam("sort", sortParam); + + // Execute the REST request + ClientResponse clientResponse = webResource.accept( + MediaType.APPLICATION_JSON).get(ClientResponse.class); + + // Get the JSON string from the response object + String responseString = clientResponse.getEntity(String.class); + + // Check the response status and report exception if one occurs + if (clientResponse.getStatus() != 200) + { + String errorMessage = ""; + if (clientResponse.getStatus() == 400) + { + errorMessage = parseJsonExceptionString(responseString); + throw new RuntimeException(errorMessage); + } + else + { + errorMessage = "Failed : HTTP error code : " + + clientResponse.getStatus(); + throw new RuntimeException(errorMessage); + } + } + + // Make redundant objects eligible for garbage collection to conserve + // memory + clientResponse = null; + client = null; + + // Process the response and return the result to the caller. + return parsePDBJsonResponse(responseString, pdbRestRequest); + } + + /** + * Process error response from PDB server if/when one occurs. + * + * @param jsonResponse + * the JSON string containing error message from the server + * @return the processed error message from the JSON string + */ + public static String parseJsonExceptionString(String jsonErrorResponse) + { + String errorMessage = "RunTime error"; + try + { + JSONParser jsonParser = new JSONParser(); + JSONObject jsonObj = (JSONObject) jsonParser.parse(jsonErrorResponse); + JSONObject errorResponse = (JSONObject) jsonObj.get("error"); + errorMessage = errorResponse.get("msg").toString(); + + JSONObject responseHeader = (JSONObject) jsonObj + .get("responseHeader"); + errorMessage += responseHeader.get("params").toString(); + } catch (ParseException e) + { + e.printStackTrace(); + } + return errorMessage; + } + + /** + * Parses the JSON response string from PDB REST API. The response is dynamic + * hence, only fields specifically requested for in the 'wantedFields' + * parameter is fetched/processed + * + * @param pdbJsonResponseString + * the JSON string to be parsed + * @param pdbRestRequest + * the request object which contains parameters used to process the + * JSON string + * @return + */ + @SuppressWarnings("unchecked") + public static PDBRestResponse parsePDBJsonResponse( + String pdbJsonResponseString, PDBRestRequest pdbRestRequest) + { + PDBRestResponse searchResult = new PDBRestResponse(); + List result = null; + try + { + JSONParser jsonParser = new JSONParser(); + JSONObject jsonObj = (JSONObject) jsonParser + .parse(pdbJsonResponseString); + + JSONObject pdbResponse = (JSONObject) jsonObj.get("response"); + String queryTime = ((JSONObject) jsonObj.get("responseHeader")).get( + "QTime").toString(); + int numFound = Integer + .valueOf(pdbResponse.get("numFound").toString()); + if (numFound > 0) + { + result = new ArrayList(); + JSONArray docs = (JSONArray) pdbResponse.get("docs"); + for (Iterator docIter = docs.iterator(); docIter + .hasNext();) + { + JSONObject doc = docIter.next(); + result.add(searchResult.new PDBResponseSummary(doc, + pdbRestRequest)); + } + searchResult.setNumberOfItemsFound(numFound); + searchResult.setResponseTime(queryTime); + searchResult.setSearchSummary(result); + } + } catch (ParseException e) + { + e.printStackTrace(); + } + return searchResult; + } + + /** + * Takes a collection of PDBDocField and converts its 'code' Field values into + * a comma delimited string. + * + * @param pdbDocfields + * the collection of PDBDocField to process + * @return the comma delimited string from the pdbDocFields collection + */ + public static String getPDBDocFieldsAsCommaDelimitedString( + Collection pdbDocfields) + { + String result = ""; + if (pdbDocfields != null && !pdbDocfields.isEmpty()) + { + StringBuilder returnedFields = new StringBuilder(); + for (PDBDocField field : pdbDocfields) + { + returnedFields.append(",").append(field.getCode()); + } + returnedFields.deleteCharAt(0); + result = returnedFields.toString(); + } + return result; + } + + /** + * Determines the column index for 'PDB Id' Fields in the dynamic summary + * table. The PDB Id serves as a unique identifier for a given row in the + * summary table + * + * @param wantedFeilds + * the available table columns in no particular order + * @return the pdb id field column index + */ + public static int getPDBIdColumIndex( + Collection wantedFeilds, boolean hasRefSeq) + { + + // If a reference sequence is attached then start counting from 1 else + // start from zero + int pdbFeildIndexCounter = hasRefSeq ? 1 : 0; + + for (PDBDocField feild : wantedFeilds) + { + if (feild.equals(PDBDocField.PDB_ID)) + { + break; // Once PDB Id index is determined exit iteration + } + ++pdbFeildIndexCounter; + } + return pdbFeildIndexCounter; + } + + /** + * This enum represents the fields available in the PDB JSON response + * + */ + public enum PDBDocField + { + PDB_ID("PDB Id", "pdb_id"), TITLE("Title", "title"), MOLECULE_NAME( + "Molecule", "molecule_name"), MOLECULE_TYPE("Molecule Type", + "molecule_type"), MOLECULE_SEQUENCE("Sequence", + "molecule_sequence"), PFAM_ACCESSION("PFAM Accession", + "pfam_accession"), PFAM_NAME("PFAM Name", "pfam_name"), INTERPRO_NAME( + "InterPro Name", "interpro_name"), INTERPRO_ACCESSION( + "InterPro Accession", "interpro_accession"), UNIPROT_ID( + "UniProt Id", "uniprot_id"), UNIPROT_ACCESSION( + "UniProt Accession", "uniprot_accession"), UNIPROT_COVERAGE( + "UniProt Coverage", "uniprot_coverage"), UNIPROT_FEATURES( + "Uniprot Features", "uniprot_features"), R_FACTOR("R Factor", + "r_factor"), RESOLUTION("Resolution", "resolution"), DATA_QUALITY( + "Data Quality", "data_quality"), OVERALL_QUALITY( + "Overall Quality", "overall_quality"), POLYMER_COUNT( + "Number of Polymers", "number_of_polymers"), PROTEIN_CHAIN_COUNT( + "Number of Protein Chains", "number_of_protein_chains"), BOUND_MOLECULE_COUNT( + "Number of Bound Molecule", "number_of_bound_molecules"), POLYMER_RESIDUE_COUNT( + "Number of Polymer Residue", "number_of_polymer_residues"), GENUS( + "GENUS", "genus"), GENE_NAME("Gene Name", "gene_name"), EXPERIMENTAL_METHOD( + "Experimental Method", "experimental_method"), GO_ID("GO Id", + "go_id"), ASSEMBLY_ID("Assembly Id", "assembly_form"), ASSEMBLY_FORM( + "Assembly Form", "assembly_id"), ASSEMBLY_TYPE("Assembly Type", + "assembly_type"), SPACE_GROUP("Space Group", "spacegroup"), CATH_CODE( + "Cath Code", "cath_code"), TAX_ID("Tax Id", "tax_id"), TAX_QUERY( + "Tax Query", "tax_query"), INTERACTING_ENTRY_ID( + "Interacting Entry Id", "interacting_entry_id"), INTERACTING_ENTITY_ID( + "Interacting Entity Id", "interacting_entity_id"), INTERACTING_MOLECULES( + "Interacting Molecules", "interacting_molecules"), PUBMED_ID( + "Pubmed Id", "pubmed_id"), STATUS("Status", "status"), MODEL_QUALITY( + "Model Quality", "model_quality"), PIVOT_RESOLUTION( + "Pivot Resolution", "pivot_resolution"), DATA_REDUCTION_SOFTWARE( + "Data reduction software", "data_reduction_software"), MAX_OBSERVED_RES( + "Max observed residues", "max_observed_residues"), ORG_SCI_NAME( + "Organism scientific name", "organism_scientific_name"), SUPER_KINGDOM( + "Super kingdom", "superkingdom"), RANK("Rank", "rank"), CRYSTALLISATION_PH( + "Crystallisation Ph", "crystallisation_ph"), BIOLOGICAL_FUNCTION( + "Biological Function", "biological_function"), BIOLOGICAL_PROCESS( + "Biological Process", "biological_process"), BIOLOGICAL_CELL_COMPONENT( + "Biological Cell Component", "biological_cell_component"), COMPOUND_NAME( + "Compound Name", "compound_name"), COMPOUND_ID("Compound Id", + "compound_id"), COMPOUND_WEIGHT("Compound Weight", + "compound_weight"), COMPOUND_SYSTEMATIC_NAME( + "Compound Systematic Name", "compound_systematic_name"), INTERACTING_LIG( + "Interacting Ligands", "interacting_ligands"), JOURNAL( + "Journal", "journal"), ALL_AUTHORS("All Authors", "all_authors"), EXPERIMENTAL_DATA_AVAILABLE( + "Experiment Data Available", "experiment_data_available"), DIFFRACTION_PROTOCOL( + "Diffraction Protocol", "diffraction_protocol"), REFINEMENT_SOFTWARE( + "Refinement Software", "refinement_software"), STRUCTURE_DETERMINATION_METHOD( + "Structure Determination Method", + "structure_determination_method"), SYNCHROTON_SITE( + "Synchrotron Site", "synchrotron_site"), SAMPLE_PREP_METHOD( + "Sample Preparation Method", "sample_preparation_method"), ENTRY_AUTHORS( + "Entry Authors", "entry_authors"), CITATION_TITLE( + "Citation Title", "citation_title"), STRUCTURE_SOLUTION_SOFTWARE( + "Structure Solution Software", "structure_solution_software"), ENTRY_ENTITY( + "Entry Entity", "entry_entity"), R_FREE("R Free", "r_free"), NO_OF_POLYMER_ENTITIES( + "Number of Polymer Entities", "number_of_polymer_entities"), NO_OF_BOUND_ENTITIES( + "Number of Bound Entities", "number_of_bound_entities"), CRYSTALLISATION_RESERVOIR( + "Crystallisation Reservoir", "crystallisation_reservoir"), DATA_SCALING_SW( + "Data Scalling Software", "data_scaling_software"), DETECTOR( + "Detector", "detector"), DETECTOR_TYPE("Detector Type", + "detector_type"), MODIFIED_RESIDUE_FLAG( + "Modified Residue Flag", "modified_residue_flag"), NUMBER_OF_COPIES( + "Number of Copies", "number_of_copies"), STRUCT_ASYM_ID( + "Struc Asym Id", "struct_asym_id"), HOMOLOGUS_PDB_ENTITY_ID( + "Homologus PDB Entity Id", "homologus_pdb_entity_id"), MOLECULE_SYNONYM( + "Molecule Synonym", "molecule_synonym"), DEPOSITION_SITE( + "Deposition Site", "deposition_site"), SYNCHROTRON_BEAMLINE( + "Synchrotron Beamline", "synchrotron_beamline"), ENTITY_ID( + "Entity Id", "entity_id"), BEAM_SOURCE_NAME("Beam Source Name", + "beam_source_name"), PROCESSING_SITE("Processing Site", + "processing_site"), ENTITY_WEIGHT("Entity Weight", + "entity_weight"), VERSION("Version", "_version_"), ALL("ALL", + "text"); + + private String name; + + private String code; + + PDBDocField(String name, String code) + { + this.name = name; + this.code = code; + } + + public String getName() + { + return name; + } + + public String getCode() + { + return code; + } + + public String toString() + { + return name; + } + } +} \ No newline at end of file diff --git a/src/jalview/ws/uimodel/PDBRestRequest.java b/src/jalview/ws/uimodel/PDBRestRequest.java new file mode 100644 index 0000000..58d7aeb --- /dev/null +++ b/src/jalview/ws/uimodel/PDBRestRequest.java @@ -0,0 +1,142 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) + * Copyright (C) 2014 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. + * + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +package jalview.ws.uimodel; + + +import jalview.ws.dbsources.PDBRestClient.PDBDocField; + +import java.util.Collection; + +/** + * Represents the PDB request to be consumed by the PDBRestClient + * + * @author tcnofoegbu + * + */ +public class PDBRestRequest +{ + private String fieldToSearchBy; + + private String searchTerm; + + private String fieldToSortBy; + + private String associatedSequence; + + private boolean allowEmptySequence; + + private int responseSize; + + private boolean isSortAscending; + + private Collection wantedFields;// = new + // Collection(); + + public String getFieldToSearchBy() + { + return fieldToSearchBy; + } + + public void setFieldToSearchBy(String fieldToSearchBy) + { + this.fieldToSearchBy = fieldToSearchBy; + } + + public String getSearchTerm() + { + return searchTerm; + } + + public void setSearchTerm(String searchTerm) + { + this.searchTerm = searchTerm; + } + + public boolean isAllowEmptySeq() + { + return allowEmptySequence; + } + + public void setAllowEmptySeq(boolean allowEmptySeq) + { + this.allowEmptySequence = allowEmptySeq; + } + + public int getResponseSize() + { + return responseSize; + } + + public void setResponseSize(int responseSize) + { + this.responseSize = responseSize; + } + + public Collection getWantedFields() + { + return wantedFields; + } + + public void setWantedFields(Collection wantedFields) + { + this.wantedFields = wantedFields; + } + + public String getFieldToSortBy() + { + return fieldToSortBy; + } + + public void setFieldToSortBy(String fieldToSortBy, boolean isSortAscending) + { + this.fieldToSortBy = fieldToSortBy; + this.isSortAscending = isSortAscending; + } + + public boolean isAscending() + { + return isSortAscending; + } + + public String getAssociatedSequence() + { + return associatedSequence; + } + + public void setAssociatedSequence(String associatedSequence) + { + this.associatedSequence = associatedSequence; + } + + public String getQuery() + { + return fieldToSearchBy + searchTerm + + (isAllowEmptySeq() ? "" : " AND molecule_sequence:['' TO *]"); + } + + public String toString() + { + return "Query : " + getQuery() + " sort field: " + fieldToSortBy + + " isAsc: " + isAscending() + " Associated Seq : " + + associatedSequence; + } +} diff --git a/src/jalview/ws/uimodel/PDBRestResponse.java b/src/jalview/ws/uimodel/PDBRestResponse.java new file mode 100644 index 0000000..3b5b05c --- /dev/null +++ b/src/jalview/ws/uimodel/PDBRestResponse.java @@ -0,0 +1,220 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) + * Copyright (C) 2014 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. + * + * 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 . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ + +package jalview.ws.uimodel; + +import jalview.ws.dbsources.PDBRestClient.PDBDocField; + +import java.util.Collection; +import java.util.Objects; + +import javax.swing.table.DefaultTableModel; + +import org.json.simple.JSONObject; + +/** + * Represents the response model produced by the PDBRestClient upon successful + * execution of a given request + * + * @author tcnofoegbu + * + */ +public class PDBRestResponse +{ + private int numberOfItemsFound; + + private String responseTime; + + private Collection searchSummary; + + public int getNumberOfItemsFound() + { + return numberOfItemsFound; + } + + public void setNumberOfItemsFound(int itemFound) + { + this.numberOfItemsFound = itemFound; + } + + public String getResponseTime() + { + return responseTime; + } + + public void setResponseTime(String responseTime) + { + this.responseTime = responseTime; + } + + public Collection getSearchSummary() + { + return searchSummary; + } + + public void setSearchSummary(Collection searchSummary) + { + this.searchSummary = searchSummary; + } + + + /** + * Convenience method to obtain a Table model for a given summary List based + * on the request parameters + * + * @param request + * the PDBRestRequest object which holds useful information for + * creating a table model + * @param summariesList + * the summary list which contains the data for populating the + * table's rows + * @return the table model which was dynamically generated + */ + public static DefaultTableModel getTableModel(PDBRestRequest request, + Collection summariesList) + { + DefaultTableModel tableModel = new DefaultTableModel(); + + if (request.getAssociatedSequence() != null) + { + tableModel.addColumn("Sequence"); // Create sequence column header if + // exists in the request + } + for (PDBDocField field : request.getWantedFields()) + { + tableModel.addColumn(field.getName()); // Create sequence column header if + // exists in the request + } + + for (PDBResponseSummary res : summariesList) + { + tableModel.addRow(res.getSummaryData()); // Populate table rows with + // summary list + } + + return tableModel; + } + + /** + * Model for a unique response summary + * + */ + public class PDBResponseSummary + { + private String pdbId; + + private String[] summaryRowData; + + private String associatedSequence; + + public PDBResponseSummary(JSONObject pdbJsonDoc, PDBRestRequest request) + { + Collection diplayFields = request.getWantedFields(); + String associatedSeq = request.getAssociatedSequence(); + int colCounter = 0; + summaryRowData = new String[(associatedSeq != null) ? diplayFields + .size() + 1 : diplayFields.size()]; + if (associatedSeq != null) + { + this.associatedSequence = (associatedSeq.length() > 18) ? associatedSeq + .substring(0, 18) : associatedSeq; + summaryRowData[0] = associatedSequence; + colCounter = 1; + } + + for (PDBDocField field : diplayFields) + { + String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? "" + : pdbJsonDoc + .get(field.getCode()).toString(); + if (field.equals(PDBDocField.PDB_ID)) + { + this.pdbId = fieldData; + summaryRowData[colCounter++] = this.pdbId; + } + else + { + summaryRowData[colCounter++] = fieldData; + } + } + } + + public String getPdbId() + { + return pdbId; + } + + public void setPdbId(String pdbId) + { + this.pdbId = pdbId; + } + + public String[] getSummaryData() + { + return summaryRowData; + } + + public void setSummaryData(String[] summaryData) + { + this.summaryRowData = summaryData; + } + + /** + * Returns a string representation of this object; + */ + @Override + public String toString() + { + StringBuilder summaryFieldValues = new StringBuilder(); + for (String summaryField : summaryRowData) + { + summaryFieldValues.append(summaryField).append("\t"); + } + return summaryFieldValues.toString(); + } + + /** + * Returns hash code value for this object + */ + @Override + public int hashCode() + { + return Objects.hash(this.pdbId, this.toString()); + } + + /** + * Indicates whether some object is equal to this one + */ + @Override + public boolean equals(Object that) + { + if (!(that instanceof PDBResponseSummary)) + { + return false; + } + PDBResponseSummary another = (PDBResponseSummary) that; + return this.toString().equals(another.toString()); + } + + } + +} + diff --git a/test/jalview/gui/PDBSearchPanelTest.java b/test/jalview/gui/PDBSearchPanelTest.java new file mode 100644 index 0000000..17ba85a --- /dev/null +++ b/test/jalview/gui/PDBSearchPanelTest.java @@ -0,0 +1,50 @@ +package jalview.gui; + +import static org.junit.Assert.assertTrue; + +import javax.swing.JInternalFrame; +import javax.swing.JTextField; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PDBSearchPanelTest +{ + + @Before + public void setUp() throws Exception + { + } + + @After + public void tearDown() throws Exception + { + } + + @Test + public void populateCmbSearchTargetOptionsTest() + { + PDBSearchPanel searchPanel = new PDBSearchPanel(null); + assertTrue(searchPanel.getCmbSearchTarget().getItemCount() > 0); + searchPanel.populateCmbSearchTargetOptions(); + } + + @Test + public void txt_search_ActionPerformedTest() + { + PDBSearchPanel searchPanel = new PDBSearchPanel(null); + JInternalFrame mainFrame = searchPanel.getMainFrame(); + JTextField txt_search = searchPanel.getTxtSearch(); + + assertTrue(mainFrame.getTitle().length() == 20); + assertTrue(mainFrame.getTitle() + .equalsIgnoreCase("PDB Sequence Fetcher")); + + txt_search.setText("ABC"); + + assertTrue(mainFrame.getTitle().length() > 20); + assertTrue(!mainFrame.getTitle().equalsIgnoreCase( + "PDB Sequence Fetcher")); + } +} diff --git a/test/jalview/gui/StructureChooserTest.java b/test/jalview/gui/StructureChooserTest.java new file mode 100644 index 0000000..24e8bc9 --- /dev/null +++ b/test/jalview/gui/StructureChooserTest.java @@ -0,0 +1,87 @@ +package jalview.gui; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.PDBEntry; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; + +import java.util.Vector; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class StructureChooserTest +{ + Sequence seq; + + @Before + public void setUp() throws Exception + { + seq = new Sequence("Test_Seq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1, 26); + seq.setDatasetSequence(seq); + for (int x = 1; x < 5; x++) + { + DBRefEntry dbRef = new DBRefEntry(); + dbRef.setAccessionId("XYZ_" + x); + seq.addDBRef(dbRef); + } + + PDBEntry dbRef = new PDBEntry(); + dbRef.setId("1tim"); + + Vector pdbIds = new Vector(); + pdbIds.add(dbRef); + + seq.setPDBId(pdbIds); + } + + @After + public void tearDown() throws Exception + { + seq = null; + } + + + + @Test + public void buildQueryTest() + { + assertEquals( + "1tim OR text:XYZ_1 OR text:XYZ_2 OR text:XYZ_3 OR text:XYZ_4", + StructureChooser.buildQuery(seq)); + } + + @Test + public void populateFilterComboBoxTest() + { + SequenceI[] selectedSeqs = new SequenceI[] + { seq }; + StructureChooser sc = new StructureChooser(selectedSeqs, seq, + null); + sc.populateFilterComboBox(); + int optionsSize = sc.getCmbFilterOption().getItemCount(); + assertEquals(2, optionsSize); // if structures are not discovered then don't + // populate filter options + + sc.setStructuresDiscovered(true); + sc.populateFilterComboBox(); + optionsSize = sc.getCmbFilterOption().getItemCount(); + assertTrue(optionsSize > 2); // if structures are found, filter options + // should be populated + } + + @Test + public void fetchStructuresInfoTest() + { + SequenceI[] selectedSeqs = new SequenceI[] + { seq }; + StructureChooser sc = new StructureChooser(selectedSeqs, seq, null); + sc.fetchStructuresMetaData(); + assertTrue(sc.getDiscoveredStructuresSet() != null); + assertTrue(sc.getDiscoveredStructuresSet().size() > 0); + + } +} diff --git a/test/jalview/io/pdb_request_json_error.txt b/test/jalview/io/pdb_request_json_error.txt new file mode 100644 index 0000000..de14bf1 --- /dev/null +++ b/test/jalview/io/pdb_request_json_error.txt @@ -0,0 +1,17 @@ +{ + "responseHeader": { + "status": 400, + "QTime": 0, + "params": { + "sort": "", + "fl": "pdb_id", + "q": "text:abc OR text:go:abc AND molecule_sequence:['' TO *]", + "wt": "json", + "rows": "100" + } + }, + "error": { + "msg": "org.apache.solr.search.SyntaxError: Cannot parse 'text:abc OR text:go:abc AND molecule_sequence:['' TO *]': Encountered \" \":\" \": \"\" at line 1, column 19.", + "code": 400 + } +} \ No newline at end of file diff --git a/test/jalview/io/pdb_response_json.txt b/test/jalview/io/pdb_response_json.txt new file mode 100644 index 0000000..e3f3583 --- /dev/null +++ b/test/jalview/io/pdb_response_json.txt @@ -0,0 +1,176 @@ +{ + "responseHeader": { + "status": 0, + "QTime": 0, + "params": { + "sort": "", + "fl": "molecule_type,pdb_id,genus,gene_name,title", + "q": "text:abc AND molecule_sequence:['' TO *]", + "wt": "json", + "rows": "100" + } + }, + "response": { + "numFound": 931, + "start": 0, + "docs": [ + { + "pdb_id": "3qf4", + "title": "Crystal structure of a heterodimeric ABC transporter in its inward-facing conformation", + "genus": [ + "Thermotoga" + ], + "molecule_type": "Protein", + "gene_name": [ + "THEMA_03290", + "Tmari_0285", + "TM_0287" + ] + }, + { + "pdb_id": "4wbs", + "title": "Crystal structure of an ABC transporter related protein from Burkholderia phymatum", + "genus": [ + "Burkholderia" + ], + "molecule_type": "Protein", + "gene_name": [ + "Bphy_0327" + ] + }, + { + "pdb_id": "1hn0", + "title": "CRYSTAL STRUCTURE OF CHONDROITIN ABC LYASE I FROM PROTEUS VULGARIS AT 1.9 ANGSTROMS RESOLUTION", + "genus": [ + "Proteus" + ], + "molecule_type": "Protein" + }, + { + "pdb_id": "4a82", + "title": "Fitted model of staphylococcus aureus sav1866 model ABC transporter in the human cystic fibrosis transmembrane conductance regulator volume map EMD-1966.", + "genus": [ + "Homo" + ], + "molecule_type": "Protein", + "gene_name": [ + "SAV1866" + ] + }, + { + "pdb_id": "3nh6", + "title": "Nucleotide Binding Domain of human ABCB6 (apo structure)", + "genus": [ + "Homo" + ], + "molecule_type": "Protein", + "gene_name": [ + "ABCB6", + "UMAT", + "MTABC3", + "PRP" + ] + }, + { + "pdb_id": "2nq2", + "title": "An inward-facing conformation of a putative metal-chelate type ABC transporter.", + "genus": [ + "Haemophilus" + ], + "molecule_type": "Protein", + "gene_name": [ + "HI_1471" + ] + }, + { + "pdb_id": "3s4u", + "title": "Crystal structure of open, unliganded E. coli PhnD H157A", + "genus": [ + "Escherichia" + ], + "molecule_type": "Protein", + "gene_name": [ + "phnD", + "UTI89_C4699" + ] + }, + { + "pdb_id": "4q4a", + "title": "Improved model of AMP-PNP bound TM287/288", + "genus": [ + "Thermotoga" + ], + "molecule_type": "Protein", + "gene_name": [ + "TM_0288" + ] + }, + { + "pdb_id": "1oxs", + "title": "Crystal structure of GlcV, the ABC-ATPase of the glucose ABC transporter from Sulfolobus solfataricus", + "genus": [ + "Sulfolobus" + ], + "molecule_type": "Protein", + "gene_name": [ + "SSO2850" + ] + }, + { + "pdb_id": "4q4j", + "title": "Structure of crosslinked TM287/288_S498C_S520C mutant", + "genus": [ + "Thermotoga" + ], + "molecule_type": "Protein", + "gene_name": [ + "TM_0288" + ] + }, + { + "pdb_id": "1oxt", + "title": "Crystal structure of GlcV, the ABC-ATPase of the glucose ABC transporter from Sulfolobus solfataricus", + "genus": [ + "Sulfolobus" + ], + "molecule_type": "Protein", + "gene_name": [ + "SSO2850" + ] + }, + { + "pdb_id": "4q4h", + "title": "TM287/288 in its apo state", + "genus": [ + "Thermotoga" + ], + "molecule_type": "Protein", + "gene_name": [ + "TM_0288" + ] + }, + { + "pdb_id": "3qf4", + "title": "Crystal structure of a heterodimeric ABC transporter in its inward-facing conformation", + "genus": [ + "Thermotoga" + ], + "molecule_type": "Protein", + "gene_name": [ + "TM_0288" + ] + }, + { + "pdb_id": "2fgk", + "title": "Crystal structure of the ABC-cassette E631Q mutant of HlyB with bound ATP", + "genus": [ + "Escherichia" + ], + "molecule_type": "Protein", + "gene_name": [ + "hlyB" + ] + } + ] + } +} \ No newline at end of file diff --git a/test/jalview/ws/dbsources/PDBRestClientTest.java b/test/jalview/ws/dbsources/PDBRestClientTest.java new file mode 100644 index 0000000..ba07562 --- /dev/null +++ b/test/jalview/ws/dbsources/PDBRestClientTest.java @@ -0,0 +1,181 @@ +package jalview.ws.dbsources; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import jalview.ws.dbsources.PDBRestClient.PDBDocField; +import jalview.ws.uimodel.PDBRestRequest; +import jalview.ws.uimodel.PDBRestResponse; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class PDBRestClientTest +{ + + @Before + public void setUp() throws Exception + { + } + + @After + public void tearDown() throws Exception + { + } + + @Test + public void executeRequestTest() + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.MOLECULE_TYPE); + wantedFields.add(PDBDocField.PDB_ID); + wantedFields.add(PDBDocField.GENUS); + wantedFields.add(PDBDocField.GENE_NAME); + wantedFields.add(PDBDocField.TITLE); + + PDBRestRequest request = new PDBRestRequest(); + request.setAllowEmptySeq(false); + request.setResponseSize(100); + request.setFieldToSearchBy("text:"); + request.setSearchTerm("abc"); + request.setWantedFields(wantedFields); + + PDBRestResponse response = new PDBRestClient().executeRequest(request); + assertTrue(response.getNumberOfItemsFound() > 99); + assertTrue(response.getSearchSummary() != null); + assertTrue(response.getSearchSummary().size() > 99); + } + + @Test + public void getPDBDocFieldsAsCommaDelimitedStringTest() + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.MOLECULE_TYPE); + wantedFields.add(PDBDocField.PDB_ID); + wantedFields.add(PDBDocField.GENUS); + wantedFields.add(PDBDocField.GENE_NAME); + wantedFields.add(PDBDocField.TITLE); + assertEquals("molecule_type,pdb_id,genus,gene_name,title", + PDBRestClient + .getPDBDocFieldsAsCommaDelimitedString(wantedFields)); + } + + @Test + public void parsePDBJsonExceptionStringTest() + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.MOLECULE_TYPE); + wantedFields.add(PDBDocField.PDB_ID); + wantedFields.add(PDBDocField.GENUS); + wantedFields.add(PDBDocField.GENE_NAME); + wantedFields.add(PDBDocField.TITLE); + + PDBRestRequest request = new PDBRestRequest(); + request.setAllowEmptySeq(false); + request.setResponseSize(100); + request.setFieldToSearchBy("text:"); + request.setSearchTerm("abc"); + request.setWantedFields(wantedFields); + + String jsonErrorResponse = ""; + try + { + jsonErrorResponse = readJsonStringFromFile("test/jalview/io/pdb_request_json_error.txt"); + } catch (IOException e) + { + e.printStackTrace(); + } + + String parsedErrorResponse = PDBRestClient + .parseJsonExceptionString(jsonErrorResponse); + String expectedErrorMsg = "org.apache.solr.search.SyntaxError: Cannot parse 'text:abc OR text:go:abc AND molecule_sequence:['' TO *]': Encountered \" \":\" \": \"\" at line 1, column 19.{\"q\":\"text:abc OR text:go:abc AND molecule_sequence:['' TO *]\",\"fl\":\"pdb_id\",\"sort\":\"\",\"rows\":\"100\",\"wt\":\"json\"}"; + + assertEquals(expectedErrorMsg, parsedErrorResponse); + } + + @Test(expected = RuntimeException.class) + public void testForExpectedRuntimeException() + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.PDB_ID); + + PDBRestRequest request = new PDBRestRequest(); + request.setFieldToSearchBy("text:"); + request.setSearchTerm("abc OR text:go:abc"); + request.setWantedFields(wantedFields); + new PDBRestClient().executeRequest(request); + } + + @Test + public void parsePDBJsonResponseTest() + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.MOLECULE_TYPE); + wantedFields.add(PDBDocField.PDB_ID); + wantedFields.add(PDBDocField.GENUS); + wantedFields.add(PDBDocField.GENE_NAME); + wantedFields.add(PDBDocField.TITLE); + + PDBRestRequest request = new PDBRestRequest(); + request.setAllowEmptySeq(false); + request.setWantedFields(wantedFields); + + String jsonString = ""; + try + { + jsonString = readJsonStringFromFile("test/jalview/io/pdb_response_json.txt"); + } catch (IOException e) + { + e.printStackTrace(); + } + PDBRestResponse response = PDBRestClient.parsePDBJsonResponse( + jsonString, request); + assertTrue(response.getSearchSummary() != null); + assertTrue(response.getNumberOfItemsFound() == 931); + assertTrue(response.getSearchSummary().size() == 14); + } + + @Test + public void getPDBIdColumIndexTest() + { + List wantedFields = new ArrayList(); + wantedFields.add(PDBDocField.MOLECULE_TYPE); + wantedFields.add(PDBDocField.GENUS); + wantedFields.add(PDBDocField.GENE_NAME); + wantedFields.add(PDBDocField.TITLE); + wantedFields.add(PDBDocField.PDB_ID); + assertEquals(5, PDBRestClient.getPDBIdColumIndex(wantedFields, true)); + assertEquals(4, PDBRestClient.getPDBIdColumIndex(wantedFields, false)); + } + + public String readJsonStringFromFile(String filePath) throws IOException + { + String fileContent; + BufferedReader br = new BufferedReader(new FileReader(filePath)); + try + { + StringBuilder sb = new StringBuilder(); + String line = br.readLine(); + + while (line != null) + { + sb.append(line); + sb.append(System.lineSeparator()); + line = br.readLine(); + } + fileContent = sb.toString(); + } finally + { + br.close(); + } + return fileContent; + } + + +}