package jalview.gui;
+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.concurrent.Executors;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
+import javax.swing.table.AbstractTableModel;
+
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.bin.Cache;
import jalview.bin.Jalview;
-import jalview.datamodel.DBRefEntry;
-import jalview.datamodel.DBRefSource;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.fts.api.FTSData;
import jalview.fts.api.FTSDataColumnI;
import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSDataColumnPreferences;
import jalview.fts.core.FTSRestRequest;
import jalview.fts.core.FTSRestResponse;
import jalview.fts.service.pdb.PDBFTSRestClient;
+import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
+import jalview.gui.structurechooser.StructureChooserQuerySource;
+import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
import jalview.io.DataSourceType;
+import jalview.jbgui.FilterOption;
import jalview.jbgui.GStructureChooser;
-import jalview.jbgui.GStructureChooser.FilterOption;
import jalview.structure.StructureMapping;
import jalview.structure.StructureSelectionManager;
import jalview.util.MessageManager;
import jalview.ws.DBRefFetcher;
+import jalview.ws.seqfetcher.DbSourceProxy;
import jalview.ws.sifts.SiftsSettings;
-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.Objects;
-import java.util.Set;
-import java.util.Vector;
-
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JTable;
-import javax.swing.SwingUtilities;
-import javax.swing.table.AbstractTableModel;
-
/**
* Provides the behaviors for the Structure chooser Panel
*
private Collection<FTSData> discoveredStructuresSet;
- private StructureChooserQuerySource data = StructureChooserQuerySource.getPDBfts();
+ private StructureChooserQuerySource data;
+
+ @Override
+ protected FTSDataColumnPreferences getFTSDocFieldPrefs()
+ {
+ return data.getDocFieldPrefs();
+ }
private String selectedPdbFileName;
private boolean cachedPDBExists;
+ private Collection<FTSData> lastDiscoveredStructuresSet;
+
private static StructureViewer lastTargetedView = null;
public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
AlignmentPanel ap)
{
+ // which FTS engine to use
+ data = StructureChooserQuerySource
+ .getQuerySourceFor(selectedSeqs);
+ initDialog();
+
this.ap = ap;
this.selectedSequence = selectedSeq;
this.selectedSequences = selectedSeqs;
this.progressIndicator = (ap == null) ? null : ap.alignFrame;
init();
+
}
/**
chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
- // ensure a filter option is in force for search
- populateFilterComboBox(true, cachedPDBExists);
- Thread discoverPDBStructuresThread = new Thread(new Runnable()
+ final Runnable discoverPDBStructures = new Runnable()
{
@Override
public void run()
{
+ // check which FTS engine to use
+ data = StructureChooserQuerySource
+ .getQuerySourceFor(selectedSequences);
+
+ // ensure a filter option is in force for search
+ populateFilterComboBox(true, cachedPDBExists);
+
+ // looks for any existing structures already loaded
+ // for the sequences (the cached ones)
+ // then queries the StructureChooserQuerySource to
+ // discover more structures.
+ //
+ // Possible optimisation is to only begin querying
+ // the structure chooser if there are no cached structures.
+
long startTime = System.currentTimeMillis();
updateProgressIndicator(MessageManager
.getString("status.loading_cached_pdb_entries"), startTime);
mainFrame.setVisible(true);
updateCurrentView();
}
- });
- discoverPDBStructuresThread.start();
+ };
+ final List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
+
+ final Runnable discoverCanonicalDBrefs = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ long progressId = System.currentTimeMillis();
+
+ int y = seqsWithoutSourceDBRef.size();
+
+ setProgressBar(MessageManager.formatMessage(
+ "status.fetching_dbrefs_for_sequences_without_valid_refs",
+ y), progressId);
+ SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
+ .toArray(new SequenceI[y]);
+
+ DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
+ progressBar, new DbSourceProxy[]
+ { new jalview.ws.dbsources.Uniprot() },
+ null, false);
+
+ dbRefFetcher.fetchDBRefs(true);
+
+ setProgressBar("Fetch complete.", progressId); // todo i18n
+
+ Executors.defaultThreadFactory().newThread(discoverPDBStructures).start();
+ }
+ };
+
+ Executors.defaultThreadFactory().newThread(new Runnable()
+ {
+ public void run()
+ {
+
+ for (SequenceI seq : selectedSequences)
+ {
+ if (seq.isProtein())
+ {
+ int dbRef = ThreeDBStructureChooserQuerySource
+ .checkUniprotRefs(seq.getDBRefs());
+ if (dbRef < 0)
+ {
+ if (seq.getAllPDBEntries()==null && seq.getAllPDBEntries().size()==0)
+ {
+ seqsWithoutSourceDBRef.add(seq);
+ }
+ }
+ }
+ }
+ // retrieve database refs for protein sequences
+ if (!seqsWithoutSourceDBRef.isEmpty())
+ {
+ // need cancel and no to result in the discoverPDB action - mocked is 'cancel'
+ JvOptionPane.newOptionDialog(Desktop.getDesktop())
+ .setResponseHandler(JvOptionPane.OK_OPTION, discoverCanonicalDBrefs)
+ .setResponseHandler(JvOptionPane.CANCEL_OPTION, discoverPDBStructures)
+ .setResponseHandler(JvOptionPane.NO_OPTION, discoverPDBStructures)
+ .showDialog(MessageManager.formatMessage("label.fetch_references_for",
+ seqsWithoutSourceDBRef.size()), MessageManager.getString(
+ "label.fetch_uniprot_references"),
+ JvOptionPane.YES_NO_OPTION,
+ JvOptionPane.PLAIN_MESSAGE, null, new Object[]
+ { MessageManager.getString("action.ok"),
+ MessageManager.getString("action.cancel") },
+ MessageManager.getString("action.ok"));
+ } else {
+ // get structures directly
+ Executors.defaultThreadFactory().newThread(discoverPDBStructures).start();
+ }
+ };
+ }).start();;
+
}
/**
if (view.isLinkedWith(ap))
{
- targetView.insertItemAt(viewHandler,
- linkedViewsAt++);
+ targetView.insertItemAt(viewHandler, linkedViewsAt++);
}
else
{
void fetchStructuresMetaData()
{
long startTime = System.currentTimeMillis();
- Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+ Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
.getStructureSummaryFields();
discoveredStructuresSet = new LinkedHashSet<>();
FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
.getSelectedItem());
-
+
for (SequenceI seq : selectedSequences)
{
FTSRestResponse resultList;
try
{
- resultList = data.fetchStructuresMetaData(seq, wantedFields, selectedFilterOpt, !chk_invertFilter.isSelected());
+ resultList = data.fetchStructuresMetaData(seq, wantedFields,
+ selectedFilterOpt, !chk_invertFilter.isSelected());
+ // null response means the FTSengine didn't yield a query for this
+ // consider designing a special exception if we really wanted to be OOCrazy
+ if (resultList==null)
+ {
+ continue;
+ }
} catch (Exception e)
{
e.printStackTrace();
if (discoveredStructuresSet != null
&& !discoveredStructuresSet.isEmpty())
{
- getResultTable().setModel(data.getTableModel(discoveredStructuresSet));
+ getResultTable()
+ .setModel(data.getTableModel(discoveredStructuresSet));
+
noOfStructuresFound = discoveredStructuresSet.size();
+ lastDiscoveredStructuresSet=discoveredStructuresSet;
mainFrame.setTitle(MessageManager.formatMessage(
"label.structure_chooser_no_of_structures",
noOfStructuresFound, totalTime));
{
Thread filterThread = new Thread(new Runnable()
{
+
@Override
public void run()
{
long startTime = System.currentTimeMillis();
lbl_loading.setVisible(true);
- Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
+ Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
.getStructureSummaryFields();
Collection<FTSData> filteredResponse = new HashSet<>();
HashSet<String> errors = new HashSet<>();
for (SequenceI seq : selectedSequences)
{
-
+
FTSRestResponse resultList;
try
{
- resultList = data.selectFirstRankedQuery(seq, wantedFields, fieldToFilterBy,
- !chk_invertFilter.isSelected());
+ resultList = data.selectFirstRankedQuery(seq, discoveredStructuresSet,wantedFields,
+ fieldToFilterBy, !chk_invertFilter.isSelected());
} catch (Exception e)
{
Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
reorderedStructuresSet.addAll(filteredResponse);
reorderedStructuresSet.addAll(discoveredStructuresSet);
- getResultTable().setModel(data.getTableModel(reorderedStructuresSet));
-
+ getResultTable()
+ .setModel(data.getTableModel(reorderedStructuresSet));
+
FTSRestResponse.configureTableColumn(getResultTable(),
wantedFields, tempUserPrefs);
getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
@Override
protected void pdbFromFile_actionPerformed()
{
- // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and StructureChooser
+ // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
+ // StructureChooser
// works
jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
protected void populateFilterComboBox(boolean haveData,
boolean cachedPDBExist)
{
+ populateFilterComboBox(haveData, cachedPDBExist, null);
+ }
+ /**
+ * Populates the filter combo-box options dynamically depending on discovered
+ * structures
+ */
+ protected void populateFilterComboBox(boolean haveData,
+ boolean cachedPDBExist, FilterOption lastSel)
+ {
+
/*
* temporarily suspend the change listener behaviour
*/
cmb_filterOption.removeItemListener(this);
-
+ int selSet=-1;
cmb_filterOption.removeAllItems();
if (haveData)
{
- cmb_filterOption.addItem(new FilterOption(
- MessageManager.getString("label.best_quality"),
- "overall_quality", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption(
- MessageManager.getString("label.best_resolution"),
- "resolution", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption(
- MessageManager.getString("label.most_protein_chain"),
- "number_of_protein_chains", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption(
- MessageManager.getString("label.most_bound_molecules"),
- "number_of_bound_molecules", VIEWS_FILTER, false));
- cmb_filterOption.addItem(new FilterOption(
- MessageManager.getString("label.most_polymer_residues"),
- "number_of_polymer_residues", VIEWS_FILTER, true));
+ List<FilterOption> filters = data.getAvailableFilterOptions(VIEWS_FILTER);
+ data.updateAvailableFilterOptions(VIEWS_FILTER, filters, lastDiscoveredStructuresSet);
+ int p=0;
+ for (FilterOption filter:filters)
+ {
+ if (lastSel!=null && filter.equals(lastSel)) {
+ selSet=p;
+ }
+ p++;
+ cmb_filterOption.addItem(filter);
+ }
}
cmb_filterOption.addItem(
new FilterOption(MessageManager.getString("label.enter_pdb_id"),
- "-", VIEWS_ENTER_ID, false));
+ "-", VIEWS_ENTER_ID, false,null));
cmb_filterOption.addItem(
new FilterOption(MessageManager.getString("label.from_file"),
- "-", VIEWS_FROM_FILE, false));
+ "-", VIEWS_FROM_FILE, false,null));
if (cachedPDBExist)
{
FilterOption cachedOption = new FilterOption(
- MessageManager.getString("label.cached_structures"),
- "-", VIEWS_LOCAL_PDB, false);
+ MessageManager.getString("label.cached_structures"), "-",
+ VIEWS_LOCAL_PDB, false,null);
cmb_filterOption.addItem(cachedOption);
- cmb_filterOption.setSelectedItem(cachedOption);
+ if (selSet==-1) {
+ cmb_filterOption.setSelectedItem(cachedOption);
+ }
+ }
+ if (selSet>-1)
+ {
+ cmb_filterOption.setSelectedIndex(selSet);
}
-
cmb_filterOption.addItemListener(this);
}
if (selectedFilterOpt.getView() == VIEWS_FILTER)
{
mainFrame.setTitle(filterTitle);
- chk_invertFilter.setVisible(true);
- filterResultSet(selectedFilterOpt.getValue());
+ // TDB Query has no invert as yet
+ chk_invertFilter.setVisible(selectedFilterOpt.getQuerySource() instanceof PDBStructureChooserQuerySource);
+
+ if (data!=selectedFilterOpt.getQuerySource() || data.needsRefetch(selectedFilterOpt))
+ {
+ data = selectedFilterOpt.getQuerySource();
+ // rebuild the views completely, since prefs will also change
+ tabRefresh();
+ return;
+ } else {
+ filterResultSet(selectedFilterOpt.getValue());
+ }
}
else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
|| selectedFilterOpt.getView() == VIEWS_FROM_FILE)
}
return found;
}
-
+
/**
* Handles the 'New View' action
*/
if (currentView == VIEWS_FILTER)
{
- int pdbIdColIndex = restable.getColumn("PDB Id")
- .getModelIndex();
- int refSeqColIndex = restable.getColumn("Ref Sequence")
- .getModelIndex();
int[] selectedRows = restable.getSelectedRows();
PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
- int count = 0;
List<SequenceI> selectedSeqsToView = new ArrayList<>();
- for (int row : selectedRows)
- {
- String pdbIdStr = restable
- .getValueAt(row, pdbIdColIndex).toString();
- SequenceI selectedSeq = (SequenceI) restable
- .getValueAt(row, refSeqColIndex);
- selectedSeqsToView.add(selectedSeq);
- PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr);
- if (pdbEntry == null)
- {
- pdbEntry = getFindEntry(pdbIdStr,
- selectedSeq.getAllPDBEntries());
- }
+ pdbEntriesToView = data.collectSelectedRows(restable,selectedRows,selectedSeqsToView);
- if (pdbEntry == null)
- {
- pdbEntry = new PDBEntry();
- pdbEntry.setId(pdbIdStr);
- pdbEntry.setType(PDBEntry.Type.PDB);
- selectedSeq.getDatasetSequence().addPDBId(pdbEntry);
- }
- pdbEntriesToView[count++] = pdbEntry;
- }
SequenceI[] selectedSeqs = selectedSeqsToView
.toArray(new SequenceI[selectedSeqsToView.size()]);
sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
List<SequenceI> selectedSeqsToView = new ArrayList<>();
for (int row : selectedRows)
{
- PDBEntry pdbEntry = (PDBEntry) tbl_local_pdb.getValueAt(row,
- pdbIdColIndex);
+ PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb.getModel()).getPDBEntryAt(row).getPdbEntry();
+
pdbEntriesToView[count++] = pdbEntry;
SequenceI selectedSeq = (SequenceI) tbl_local_pdb
.getValueAt(row, refSeqColIndex);
DataSourceType.FILE, selectedSequence, true,
Desktop.instance);
- sViewer = launchStructureViewer(
- ssm, new PDBEntry[]
- { fileEntry }, ap,
- new SequenceI[]
+ sViewer = launchStructureViewer(ssm, new PDBEntry[] { fileEntry },
+ ap, new SequenceI[]
{ selectedSequence });
}
SwingUtilities.invokeLater(new Runnable()
}
}
- private PDBEntry getFindEntry(String id, Vector<PDBEntry> pdbEntries)
- {
- Objects.requireNonNull(id);
- Objects.requireNonNull(pdbEntries);
- PDBEntry foundEntry = null;
- for (PDBEntry entry : pdbEntries)
- {
- if (entry.getId().equalsIgnoreCase(id))
- {
- return entry;
- }
- }
- return foundEntry;
- }
-
/**
* Answers a structure viewer (new or existing) configured to superimpose
* added structures or not according to the user's choice
* @param ssm
* @return
*/
- StructureViewer getTargetedStructureViewer(
- StructureSelectionManager ssm)
+ StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
{
Object sv = targetView.getSelectedItem();
* @return
*/
private StructureViewer launchStructureViewer(
- StructureSelectionManager ssm,
- final PDBEntry[] pdbEntriesToView,
+ StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
final AlignmentPanel alignPanel, SequenceI[] sequences)
{
long progressId = sequences.hashCode();
}
if (pdbEntriesToView.length > 1)
{
- setProgressBar(MessageManager.getString(
- "status.fetching_3d_structures_for_selected_entries"),
+ setProgressBar(
+ MessageManager.getString(
+ "status.fetching_3d_structures_for_selected_entries"),
progressId);
theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
}
{
setProgressBar(MessageManager.formatMessage(
"status.fetching_3d_structures_for",
- pdbEntriesToView[0].getId()),progressId);
+ pdbEntriesToView[0].getId()), progressId);
theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
}
setProgressBar(null, progressId);
&& !discoveredStructuresSet.isEmpty();
}
- protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes this.
+ protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
+ // this.
// Doing a search for "1" or "1c" is valuable?
// Those work but are enormously slow.
protected void txt_search_ActionPerformed()
{
String text = txt_search.getText().trim();
- if (text.length() >= PDB_ID_MIN)
- new Thread()
- {
-
- @Override
- public void run()
+ if (text.length() >= PDB_ID_MIN)
+ new Thread()
{
- errorWarning.setLength(0);
- isValidPBDEntry = false;
- if (text.length() > 0)
+
+ @Override
+ public void run()
{
- // TODO move this pdb id search into the PDB specific FTSSearchEngine
- // for moment, it will work fine as is because it is self-contained
- String searchTerm = text.toLowerCase();
- searchTerm = searchTerm.split(":")[0];
- // System.out.println(">>>>> search term : " + searchTerm);
- List<FTSDataColumnI> wantedFields = new ArrayList<>();
- FTSRestRequest pdbRequest = new FTSRestRequest();
- pdbRequest.setAllowEmptySeq(false);
- pdbRequest.setResponseSize(1);
- pdbRequest.setFieldToSearchBy("(pdb_id:");
- pdbRequest.setWantedFields(wantedFields);
- pdbRequest.setSearchTerm(searchTerm + ")");
- pdbRequest.setAssociatedSequence(selectedSequence);
- FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
- wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
- FTSRestResponse resultList;
- try
+ errorWarning.setLength(0);
+ isValidPBDEntry = false;
+ if (text.length() > 0)
{
- resultList = pdbRestClient.executeRequest(pdbRequest);
- } catch (Exception e)
- {
- errorWarning.append(e.getMessage());
- return;
- } finally
- {
- validateSelections();
- }
- if (resultList.getSearchSummary() != null
- && resultList.getSearchSummary().size() > 0)
- {
- isValidPBDEntry = true;
+ // TODO move this pdb id search into the PDB specific
+ // FTSSearchEngine
+ // for moment, it will work fine as is because it is self-contained
+ String searchTerm = text.toLowerCase();
+ searchTerm = searchTerm.split(":")[0];
+ // System.out.println(">>>>> search term : " + searchTerm);
+ List<FTSDataColumnI> wantedFields = new ArrayList<>();
+ FTSRestRequest pdbRequest = new FTSRestRequest();
+ pdbRequest.setAllowEmptySeq(false);
+ pdbRequest.setResponseSize(1);
+ pdbRequest.setFieldToSearchBy("(pdb_id:");
+ pdbRequest.setWantedFields(wantedFields);
+ pdbRequest.setSearchTerm(searchTerm + ")");
+ pdbRequest.setAssociatedSequence(selectedSequence);
+ FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
+ wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
+ FTSRestResponse resultList;
+ try
+ {
+ resultList = pdbRestClient.executeRequest(pdbRequest);
+ } catch (Exception e)
+ {
+ errorWarning.append(e.getMessage());
+ return;
+ } finally
+ {
+ validateSelections();
+ }
+ if (resultList.getSearchSummary() != null
+ && resultList.getSearchSummary().size() > 0)
+ {
+ isValidPBDEntry = true;
+ }
}
+ validateSelections();
}
- validateSelections();
- }
- }.start();
+ }.start();
}
@Override
public void run()
{
fetchStructuresMetaData();
+ //populateFilterComboBox(true, cachedPDBExists);
+
filterResultSet(
((FilterOption) cmb_filterOption.getSelectedItem())
.getValue());
value = entry.getSequence();
break;
case 1:
- value = entry.getPdbEntry();
+ value = entry.getQualifiedId();
break;
case 2:
value = entry.getPdbEntry().getChainCode() == null ? "_"
this.pdbEntry = pdbEntry;
}
+ public String getQualifiedId()
+ {
+ if (pdbEntry.hasProvider())
+ {
+ return pdbEntry.getProvider()+":"+pdbEntry.getId();
+ }
+ return pdbEntry.toString();
+ }
+
public SequenceI getSequence()
{
return sequence;
{
return sViewer == null ? null : sViewer.sview;
}
+
+ @Override
+ protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
+ {
+ data.setDocFieldPrefs(newPrefs);
+
+ }
+
+ /**
+ *
+ * @return true when all initialisation threads have finished and dialog is visible
+ */
+ public boolean isDialogVisible()
+ {
+ return mainFrame != null && data != null && cmb_filterOption != null
+ && mainFrame.isVisible()
+ && cmb_filterOption.getSelectedItem() != null;
+ }
}