/* * 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.structure.StructureSelectionManager; 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.Hashtable; import java.util.LinkedHashSet; import java.util.List; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.table.DefaultTableModel; /** * 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; private static Hashtable cachedEntryMap; 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); loadLocalCachedPDBEntries(); 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 + ")"); } public void loadLocalCachedPDBEntries() { DefaultTableModel tableModel = new DefaultTableModel(); tableModel.addColumn("Sequence"); tableModel.addColumn("PDB Id"); tableModel.addColumn("Type"); tableModel.addColumn("File"); cachedEntryMap = new Hashtable(); for (SequenceI seq : selectedSequences) { if (seq.getDatasetSequence() != null && seq.getDatasetSequence().getPDBId() != null) { for (PDBEntry pdbEntry : seq.getDatasetSequence().getPDBId()) { String[] pdbEntryRowData = new String[] { seq.getDisplayId(false), pdbEntry.getId(), pdbEntry.getType(), pdbEntry.getFile() }; tableModel.addRow(pdbEntryRowData); cachedEntryMap.put(seq.getDisplayId(false) + pdbEntry.getId(), pdbEntry); } } } tbl_local_pdb.setModel(tableModel); } /** * 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 */ public static String buildQuery(SequenceI seq) { HashSet seqRefs = new LinkedHashSet(); String seqName = seq.getName(); String[] names = seqName.toLowerCase().split("\\|"); for (String name : names) { System.out.println("Found name : " + name); name.trim(); if (isValidSeqName(name)) { seqRefs.add(name); } } if (seq.getPDBId() != null) { for (PDBEntry entry : seq.getPDBId()) { seqRefs.add(entry.getId()); } } if (seq.getDBRef() != null && seq.getDBRef().length != 0) { int count = 0; for (DBRefEntry dbRef : seq.getDBRef()) { seqRefs.add(getDBRefId(dbRef)); ++count; if (count > 10) { break; } } } StringBuilder queryBuilder = new StringBuilder(); for (String seqRef : seqRefs) { queryBuilder.append("text:").append(seqRef).append(" OR "); } int endIndex = queryBuilder.lastIndexOf(" OR "); String query = queryBuilder.toString().substring(5, endIndex); return query; } /** * Ensures sequence ref names are not less than 3 characters and does not * contain a database name * * @param seqName * @return */ public static boolean isValidSeqName(String seqName) { String ignoreList = "pdb,uniprot"; if (seqName.length() < 3) { return false; } for (String ignoredEntry : ignoreList.split(",")) { if (seqName.equalsIgnoreCase(ignoredEntry)) { return false; } } return true; } public static String getDBRefId(DBRefEntry dbRef) { String ref = dbRef.getAccessionId().replaceAll("GO:", ""); return ref; } /** * 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)); cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-", VIEWS_LOCAL_PDB)); } /** * 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 if (selectedFilterOpt.getView() == VIEWS_ENTER_ID || selectedFilterOpt.getView() == VIEWS_FROM_FILE) { 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_LOCAL_PDB) { if (tbl_local_pdb.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; } launchStructureViewer(ap.getStructureSelectionManager(), pdbEntriesToView, ap, selectedSequences); } else if(currentView == VIEWS_LOCAL_PDB){ int[] selectedRows = tbl_local_pdb.getSelectedRows(); PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length]; int count = 0; for (int row : selectedRows) { String entryKey = tbl_local_pdb.getValueAt(row, 0).toString() + tbl_local_pdb.getValueAt(row, 1).toString(); pdbEntriesToView[count++] = cachedEntryMap.get(entryKey); } launchStructureViewer(ap.getStructureSelectionManager(), pdbEntriesToView, ap, selectedSequences); } else if (currentView == VIEWS_ENTER_ID) { SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel .getCmb_assSeq().getSelectedItem()).getSequence(); if (userSelectedSeq != null) { selectedSequence = userSelectedSeq; } PDBEntry pdbEntry = new PDBEntry(); pdbEntry.setId(txt_search.getText()); pdbEntry.setType("PDB"); selectedSequence.getDatasetSequence().addPDBId(pdbEntry); PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry }; launchStructureViewer(ap.getStructureSelectionManager(), pdbEntriesToView, ap, new SequenceI[] { selectedSequence }); } else if (currentView == VIEWS_FROM_FILE) { SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel .getCmb_assSeq().getSelectedItem()).getSequence(); if (userSelectedSeq != null) { selectedSequence = userSelectedSeq; } PDBEntry fileEntry = new AssociatePdbFileWithSeq() .associatePdbWithSeq( selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE, selectedSequence, true, Desktop.instance); launchStructureViewer(ap.getStructureSelectionManager(), new PDBEntry[] { fileEntry }, ap, new SequenceI[] { selectedSequence }); } mainFrame.dispose(); } private void launchStructureViewer(StructureSelectionManager ssm, PDBEntry[] pdbEntriesToView, AlignmentPanel alignPanel, SequenceI[] selectedSequences) { StructureViewer sViewer = new StructureViewer(ssm); if (pdbEntriesToView.length > 1) { sViewer.viewStructures(alignPanel, pdbEntriesToView, alignPanel.av.collateForPDB(pdbEntriesToView)); } else { sViewer.viewStructures(pdbEntriesToView[0], selectedSequences, null, alignPanel); } } /** * 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(); } } }