2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.awt.event.ItemEvent;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.HashSet;
31 import java.util.LinkedHashMap;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Locale;
36 import java.util.concurrent.Executors;
38 import javax.swing.JCheckBox;
39 import javax.swing.JComboBox;
40 import javax.swing.JLabel;
41 import javax.swing.JMenuItem;
42 import javax.swing.JPopupMenu;
43 import javax.swing.JProgressBar;
44 import javax.swing.JTable;
45 import javax.swing.SwingUtilities;
46 import javax.swing.table.AbstractTableModel;
48 import com.stevesoft.pat.Regex;
50 import jalview.analysis.AlignmentUtils;
51 import jalview.api.AlignmentViewPanel;
52 import jalview.api.structures.JalviewStructureDisplayI;
53 import jalview.bin.Cache;
54 import jalview.bin.Console;
55 import jalview.bin.Jalview;
56 import jalview.datamodel.AlignmentAnnotation;
57 import jalview.datamodel.AlignmentI;
58 import jalview.datamodel.PDBEntry;
59 import jalview.datamodel.SequenceGroup;
60 import jalview.datamodel.SequenceI;
61 import jalview.ext.jmol.JmolParser;
62 import jalview.fts.api.FTSData;
63 import jalview.fts.api.FTSDataColumnI;
64 import jalview.fts.api.FTSRestClientI;
65 import jalview.fts.core.FTSDataColumnPreferences;
66 import jalview.fts.core.FTSRestRequest;
67 import jalview.fts.core.FTSRestResponse;
68 import jalview.fts.service.pdb.PDBFTSRestClient;
69 import jalview.fts.service.threedbeacons.TDB_FTSData;
70 import jalview.gui.StructureViewer.ViewerType;
71 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
72 import jalview.gui.structurechooser.StructureChooserQuerySource;
73 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
74 import jalview.io.DataSourceType;
75 import jalview.io.JalviewFileChooser;
76 import jalview.io.JalviewFileView;
77 import jalview.jbgui.FilterOption;
78 import jalview.jbgui.GStructureChooser;
79 import jalview.structure.StructureImportSettings.TFType;
80 import jalview.structure.StructureMapping;
81 import jalview.structure.StructureSelectionManager;
82 import jalview.util.MessageManager;
83 import jalview.util.Platform;
84 import jalview.util.StringUtils;
85 import jalview.ws.DBRefFetcher;
86 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
87 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
88 import jalview.ws.seqfetcher.DbSourceProxy;
89 import jalview.ws.sifts.SiftsSettings;
92 * Provides the behaviors for the Structure chooser Panel
97 @SuppressWarnings("serial")
98 public class StructureChooser extends GStructureChooser
99 implements IProgressIndicator
101 private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
104 * warn user if need to fetch more than this many uniprot records at once
106 private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
108 private SequenceI selectedSequence;
110 private SequenceI[] selectedSequences;
112 private IProgressIndicator progressIndicator;
114 private Collection<FTSData> discoveredStructuresSet;
116 private StructureChooserQuerySource data;
119 protected FTSDataColumnPreferences getFTSDocFieldPrefs()
121 return data.getDocFieldPrefs();
124 private String selectedPdbFileName;
126 private TFType localPdbTempfacType;
128 private String localPdbPaeMatrixFileName;
130 private boolean isValidPBDEntry;
132 private boolean cachedPDBExists;
134 private Collection<FTSData> lastDiscoveredStructuresSet;
136 private boolean canQueryTDB = false;
138 private boolean notQueriedTDBYet = true;
140 List<SequenceI> seqsWithoutSourceDBRef = null;
142 private boolean showChooserGUI = true;
145 * when true, queries to external services are supressed (no SIFTs, no PDBe,
146 * no 3D-Beacons, etc)
148 private boolean dontQueryServices = false;
150 private static StructureViewer lastTargetedView = null;
152 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
155 this(selectedSeqs, selectedSeq, ap, true);
158 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
159 AlignmentPanel ap, boolean showGUI)
161 this(selectedSeqs, selectedSeq, ap, showGUI, false);
164 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
165 AlignmentPanel ap, boolean showGUI, boolean dontQueryServices)
168 // which FTS engine to use
169 data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
173 this.selectedSequence = selectedSeq;
174 this.selectedSequences = selectedSeqs;
175 this.progressIndicator = (ap == null) ? null : ap.alignFrame;
176 this.showChooserGUI = showGUI;
177 this.dontQueryServices = dontQueryServices;
183 * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
184 * least one structure are discovered.
186 private void populateSeqsWithoutSourceDBRef()
188 seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
189 boolean needCanonical = false;
190 for (SequenceI seq : selectedSequences)
194 int dbRef = ThreeDBStructureChooserQuerySource
195 .checkUniprotRefs(seq.getDBRefs());
200 // need to retrieve canonicals
201 needCanonical = true;
202 seqsWithoutSourceDBRef.add(seq);
206 // could be a sequence with pdb ref
207 if (seq.getAllPDBEntries() == null
208 || seq.getAllPDBEntries().size() == 0)
210 seqsWithoutSourceDBRef.add(seq);
216 // retrieve database refs for protein sequences
217 if (!seqsWithoutSourceDBRef.isEmpty())
222 // triggers display of the 'Query TDB' button
223 notQueriedTDBYet = true;
229 * Initializes parameters used by the Structure Chooser Panel
231 protected void init()
233 if (!Jalview.isHeadlessMode())
235 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
238 chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
239 btn_queryTDB.addActionListener(new ActionListener()
243 public void actionPerformed(ActionEvent e)
245 promptForTDBFetch(false);
249 if (!dontQueryServices)
251 Executors.defaultThreadFactory().newThread(new Runnable()
256 populateSeqsWithoutSourceDBRef();
257 initialStructureDiscovery();
265 "Structure chooser not querying services to discover metadata.");
270 private void initialStructureDiscovery()
272 // check which FTS engine to use
273 data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
275 // ensure a filter option is in force for search
276 populateFilterComboBox(true, cachedPDBExists);
278 // looks for any existing structures already loaded
279 // for the sequences (the cached ones)
280 // then queries the StructureChooserQuerySource to
281 // discover more structures.
283 // Possible optimisation is to only begin querying
284 // the structure chooser if there are no cached structures.
286 long startTime = System.currentTimeMillis();
287 updateProgressIndicator(
288 MessageManager.getString("status.loading_cached_pdb_entries"),
290 loadLocalCachedPDBEntries();
291 updateProgressIndicator(null, startTime);
292 updateProgressIndicator(
293 MessageManager.getString("status.searching_for_pdb_structures"),
295 fetchStructuresMetaData();
296 // revise filter options if no results were found
297 populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
298 discoverStructureViews();
299 updateProgressIndicator(null, startTime);
300 mainFrame.setVisible(showChooserGUI);
305 * raises dialog for Uniprot fetch followed by 3D beacons search
308 * - when true, don't ask, just fetch
310 public void promptForTDBFetch(boolean ignoreGui)
312 final long progressId = System.currentTimeMillis();
314 // final action after prompting and discovering db refs
315 final Runnable strucDiscovery = new Runnable()
320 mainFrame.setEnabled(false);
321 cmb_filterOption.setEnabled(false);
322 progressBar.setProgressBar(
323 MessageManager.getString("status.searching_3d_beacons"),
325 btn_queryTDB.setEnabled(false);
326 // TODO: warn if no accessions discovered
327 populateSeqsWithoutSourceDBRef();
328 // redo initial discovery - this time with 3d beacons
330 previousWantedFields = null;
331 lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
332 cmb_filterOption.setSelectedItem(null);
333 cachedPDBExists = false; // reset to initial
334 initialStructureDiscovery();
335 if (!isStructuresDiscovered())
337 progressBar.setProgressBar(MessageManager.getString(
338 "status.no_structures_discovered_from_3d_beacons"),
340 btn_queryTDB.setToolTipText(MessageManager.getString(
341 "status.no_structures_discovered_from_3d_beacons"));
342 btn_queryTDB.setEnabled(false);
343 pnl_queryTDB.setVisible(false);
347 cmb_filterOption.setSelectedIndex(0); // select 'best'
348 btn_queryTDB.setVisible(false);
349 pnl_queryTDB.setVisible(false);
350 progressBar.setProgressBar(null, progressId);
352 mainFrame.setEnabled(true);
353 cmb_filterOption.setEnabled(true);
357 final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
361 public void finished()
363 // filter has been selected, so we set flag to remove ourselves
364 notQueriedTDBYet = false;
365 // new thread to discover structures - via 3d beacons
366 Executors.defaultThreadFactory().newThread(strucDiscovery).start();
371 // fetch db refs if OK pressed
372 final Runnable discoverCanonicalDBrefs = () -> {
373 btn_queryTDB.setEnabled(false);
374 populateSeqsWithoutSourceDBRef();
376 final int y = seqsWithoutSourceDBRef.size();
379 final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
380 .toArray(new SequenceI[y]);
381 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
382 progressBar, new DbSourceProxy[]
383 { new jalview.ws.dbsources.Uniprot() }, null, false);
384 dbRefFetcher.addListener(afterDbRefFetch);
385 // ideally this would also gracefully run with callbacks
387 dbRefFetcher.fetchDBRefs(true);
391 // call finished action directly
392 afterDbRefFetch.finished();
395 final Runnable revertview = () -> {
396 if (lastSelected != null)
398 cmb_filterOption.setSelectedItem(lastSelected);
401 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
402 THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
403 Console.debug("Using Uniprot fetch threshold of " + threshold);
404 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
406 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
409 // need cancel and no to result in the discoverPDB action - mocked is
410 // 'cancel' TODO: mock should be OK
412 StructureChooser thisSC = this;
413 JvOptionPane.newOptionDialog(thisSC.getFrame())
414 .setResponseHandler(JvOptionPane.OK_OPTION,
415 discoverCanonicalDBrefs)
416 .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
417 .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
419 MessageManager.formatMessage(
420 "label.fetch_references_for_3dbeacons",
421 seqsWithoutSourceDBRef.size()),
422 MessageManager.getString("label.3dbeacons"),
423 JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
425 { MessageManager.getString("action.ok"),
426 MessageManager.getString("action.cancel") },
427 MessageManager.getString("action.ok"), false);
431 * Builds a drop-down choice list of existing structure viewers to which new
432 * structures may be added. If this list is empty then it, and the 'Add'
433 * button, are hidden.
435 private void discoverStructureViews()
437 if (Desktop.instance != null)
439 targetView.removeAllItems();
440 if (lastTargetedView != null && !lastTargetedView.isVisible())
442 lastTargetedView = null;
444 int linkedViewsAt = 0;
445 for (StructureViewerBase view : Desktop.instance
446 .getStructureViewers(null, null))
448 StructureViewer viewHandler = (lastTargetedView != null
449 && lastTargetedView.sview == view) ? lastTargetedView
450 : StructureViewer.reconfigure(view);
452 if (view.isLinkedWith(ap))
454 targetView.insertItemAt(viewHandler, linkedViewsAt++);
458 targetView.addItem(viewHandler);
463 * show option to Add to viewer if at least 1 viewer found
465 targetView.setVisible(false);
466 if (targetView.getItemCount() > 0)
468 targetView.setVisible(true);
469 if (lastTargetedView != null)
471 targetView.setSelectedItem(lastTargetedView);
475 targetView.setSelectedIndex(0);
478 btn_add.setVisible(targetView.isVisible());
483 * Updates the progress indicator with the specified message
486 * displayed message for the operation
488 * unique handle for this indicator
490 protected void updateProgressIndicator(String message, long id)
492 if (progressIndicator != null)
494 progressIndicator.setProgressBar(message, id);
499 * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
502 void fetchStructuresMetaData()
504 long startTime = System.currentTimeMillis();
505 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
506 .getStructureSummaryFields();
508 discoveredStructuresSet = new LinkedHashSet<>();
509 HashSet<String> errors = new HashSet<>();
511 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
514 for (SequenceI seq : selectedSequences)
517 FTSRestResponse resultList;
520 resultList = data.fetchStructuresMetaData(seq, wantedFields,
521 selectedFilterOpt, !chk_invertFilter.isSelected());
522 // null response means the FTSengine didn't yield a query for this
523 // consider designing a special exception if we really wanted to be
525 if (resultList == null)
529 } catch (Exception e)
531 Console.printStackTrace(e);
532 errors.add(e.getMessage());
535 if (resultList.getSearchSummary() != null
536 && !resultList.getSearchSummary().isEmpty())
538 discoveredStructuresSet.addAll(resultList.getSearchSummary());
542 int noOfStructuresFound = 0;
543 String totalTime = (System.currentTimeMillis() - startTime)
545 if (discoveredStructuresSet != null
546 && !discoveredStructuresSet.isEmpty())
549 .setModel(data.getTableModel(discoveredStructuresSet));
551 noOfStructuresFound = discoveredStructuresSet.size();
552 lastDiscoveredStructuresSet = discoveredStructuresSet;
553 mainFrame.setTitle(MessageManager.formatMessage(
554 "label.structure_chooser_no_of_structures",
555 noOfStructuresFound, totalTime));
559 mainFrame.setTitle(MessageManager
560 .getString("label.structure_chooser_manual_association"));
561 if (errors.size() > 0)
563 StringBuilder errorMsg = new StringBuilder();
564 for (String error : errors)
566 errorMsg.append(error).append("\n");
568 if (!Jalview.isHeadlessMode())
570 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
571 MessageManager.getString("label.pdb_web-service_error"),
572 JvOptionPane.ERROR_MESSAGE);
577 MessageManager.getString("label.pdb_web-service_error"));
578 Console.debug(errorMsg.toString());
584 protected void loadLocalCachedPDBEntries()
586 ArrayList<CachedPDB> entries = new ArrayList<>();
587 for (SequenceI seq : selectedSequences)
589 if (seq.getDatasetSequence() != null
590 && seq.getDatasetSequence().getAllPDBEntries() != null)
592 for (PDBEntry pdbEntry : seq.getDatasetSequence()
595 if (pdbEntry.getFile() != null)
597 entries.add(new CachedPDB(seq, pdbEntry));
602 cachedPDBExists = !entries.isEmpty();
603 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
604 tbl_local_pdb.setModel(tableModelx);
608 * Filters a given list of discovered structures based on supplied argument
610 * @param fieldToFilterBy
611 * the field to filter by
613 void filterResultSet(final String fieldToFilterBy)
615 Thread filterThread = new Thread(new Runnable()
621 long startTime = System.currentTimeMillis();
622 lbl_loading.setVisible(true);
623 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
624 .getStructureSummaryFields();
625 Collection<FTSData> filteredResponse = new HashSet<>();
626 HashSet<String> errors = new HashSet<>();
628 for (SequenceI seq : selectedSequences)
631 FTSRestResponse resultList;
634 resultList = data.selectFirstRankedQuery(seq,
635 discoveredStructuresSet, wantedFields, fieldToFilterBy,
636 !chk_invertFilter.isSelected());
638 } catch (Exception e)
640 Console.debugPrintStackTrace(e);
641 errors.add(e.getMessage());
644 if (resultList.getSearchSummary() != null
645 && !resultList.getSearchSummary().isEmpty())
647 filteredResponse.addAll(resultList.getSearchSummary());
651 String totalTime = (System.currentTimeMillis() - startTime)
653 if (!filteredResponse.isEmpty())
655 final int filterResponseCount = filteredResponse.size();
656 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
657 reorderedStructuresSet.addAll(filteredResponse);
658 reorderedStructuresSet.addAll(discoveredStructuresSet);
660 .setModel(data.getTableModel(reorderedStructuresSet));
662 FTSRestResponse.configureTableColumn(getResultTable(),
663 wantedFields, tempUserPrefs);
664 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
665 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
666 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
667 // Update table selection model here
668 getResultTable().addRowSelectionInterval(0,
669 filterResponseCount - 1);
670 mainFrame.setTitle(MessageManager.formatMessage(
671 "label.structure_chooser_filter_time", totalTime));
675 mainFrame.setTitle(MessageManager.formatMessage(
676 "label.structure_chooser_filter_time", totalTime));
677 if (errors.size() > 0)
679 StringBuilder errorMsg = new StringBuilder();
680 for (String error : errors)
682 errorMsg.append(error).append("\n");
684 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
685 MessageManager.getString("label.pdb_web-service_error"),
686 JvOptionPane.ERROR_MESSAGE);
690 lbl_loading.setVisible(false);
692 validateSelections();
695 filterThread.start();
699 * Handles action event for btn_pdbFromFile
702 protected void pdbFromFile_actionPerformed()
704 // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
707 JalviewFileChooser chooser = new JalviewFileChooser(
708 Cache.getProperty("LAST_DIRECTORY"));
709 chooser.setFileView(new JalviewFileView());
710 chooser.setDialogTitle(
711 MessageManager.formatMessage("label.select_pdb_file_for",
712 selectedSequence.getDisplayId(false)));
713 chooser.setToolTipText(MessageManager.formatMessage(
714 "label.load_pdb_file_associate_with_sequence",
715 selectedSequence.getDisplayId(false)));
717 int value = chooser.showOpenDialog(null);
718 if (value == JalviewFileChooser.APPROVE_OPTION)
720 selectedPdbFileName = chooser.getSelectedFile().getPath();
721 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
722 boolean guessTFType = localPdbPaeMatrixFileName == null;
723 localPdbPaeMatrixFileName = guessPAEFilename();
724 guessTFType |= localPdbPaeMatrixFileName != null;
725 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
727 && alphaFold.search(new File(selectedPdbFileName).getName())
728 && !tempFacAsChanged)
730 // localPdbPaeMatrixFileName was null and now isn't and filename could
731 // well be AlphaFold and user hasn't adjusted the tempFacType
732 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
734 validateSelections();
739 * Handles action event for btn_paeMatrixFile
742 protected void paeMatrixFile_actionPerformed()
744 File pdbFile = new File(selectedPdbFileName);
745 String setFile = Cache.getProperty("LAST_DIRECTORY");
746 if (localPdbPaeMatrixFileName != null)
748 File paeFile = new File(localPdbPaeMatrixFileName);
749 if (paeFile.exists())
750 setFile = paeFile.getAbsolutePath();
751 else if (paeFile.getParentFile().exists())
752 setFile = paeFile.getParentFile().getAbsolutePath();
756 String guess = guessPAEFilename();
760 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
761 chooser.setFileView(new JalviewFileView());
762 chooser.setDialogTitle(MessageManager.formatMessage(
763 "label.select_pae_matrix_file_for", pdbFile.getName()));
764 chooser.setToolTipText(MessageManager.formatMessage(
765 "label.load_pae_matrix_file_associate_with_structure",
768 // TODO convert to Callable/Promise
769 int value = chooser.showOpenDialog(null);
770 if (value == JalviewFileChooser.APPROVE_OPTION)
772 String fileName = chooser.getSelectedFile().getPath();
775 PAEContactMatrix.validateContactMatrixFile(fileName);
776 } catch (Exception thr)
778 JvOptionPane.showInternalMessageDialog(this, MessageManager
779 .formatMessage("label.couldnt_load_file", new Object[]
780 { fileName }) + "<br>" + thr.getLocalizedMessage(),
781 MessageManager.getString("label.error_loading_file"),
782 JvOptionPane.WARNING_MESSAGE);
783 Console.error("Couldn't import " + fileName + " as a PAE matrix",
787 localPdbPaeMatrixFileName = fileName;
788 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
790 validateAssociationFromFile();
793 private String guessPAEFilename()
795 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
796 || selectedPdbFileName.toLowerCase(Locale.ROOT)
799 String jsonExt = selectedPdbFileName.substring(0,
800 selectedPdbFileName.length() - 4) + ".json";
801 // AlphaFold naming scheme
802 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
803 "predicted_aligned_error");
804 // nf-core mode naming scheme
805 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
807 if (new File(guessFile1).exists())
811 else if (new File(jsonExt).exists())
815 else if (new File(guessFile2).exists())
824 * Populates the filter combo-box options dynamically depending on discovered
827 protected void populateFilterComboBox(boolean haveData,
828 boolean cachedPDBExist)
830 populateFilterComboBox(haveData, cachedPDBExist, null);
834 * Populates the filter combo-box options dynamically depending on discovered
837 protected void populateFilterComboBox(boolean haveData,
838 boolean cachedPDBExist, FilterOption lastSel)
842 * temporarily suspend the change listener behaviour
844 cmb_filterOption.removeItemListener(this);
846 cmb_filterOption.removeAllItems();
849 List<FilterOption> filters = data
850 .getAvailableFilterOptions(VIEWS_FILTER);
851 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
852 lastDiscoveredStructuresSet);
854 for (FilterOption filter : filters)
856 if (lastSel != null && filter.equals(lastSel))
861 cmb_filterOption.addItem(filter);
865 cmb_filterOption.addItem(
866 new FilterOption(MessageManager.getString("label.enter_pdb_id"),
867 "-", VIEWS_ENTER_ID, false, null));
868 cmb_filterOption.addItem(
869 new FilterOption(MessageManager.getString("label.from_file"),
870 "-", VIEWS_FROM_FILE, false, null));
871 if (canQueryTDB && notQueriedTDBYet)
873 btn_queryTDB.setVisible(true);
874 pnl_queryTDB.setVisible(true);
879 FilterOption cachedOption = new FilterOption(
880 MessageManager.getString("label.cached_structures"), "-",
881 VIEWS_LOCAL_PDB, false, null);
882 cmb_filterOption.addItem(cachedOption);
885 cmb_filterOption.setSelectedItem(cachedOption);
890 cmb_filterOption.setSelectedIndex(selSet);
892 cmb_filterOption.addItemListener(this);
896 * Updates the displayed view based on the selected filter option
898 protected void updateCurrentView()
900 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
903 if (lastSelected == selectedFilterOpt)
905 // don't need to do anything, probably
908 // otherwise, record selection
909 // and update the layout and dialog accordingly
910 lastSelected = selectedFilterOpt;
912 layout_switchableViews.show(pnl_switchableViews,
913 selectedFilterOpt.getView());
914 String filterTitle = mainFrame.getTitle();
915 mainFrame.setTitle(frameTitle);
916 chk_invertFilter.setVisible(false);
918 if (selectedFilterOpt.getView() == VIEWS_FILTER)
920 mainFrame.setTitle(filterTitle);
921 // TDB Query has no invert as yet
922 chk_invertFilter.setVisible(selectedFilterOpt
923 .getQuerySource() instanceof PDBStructureChooserQuerySource);
925 if (data != selectedFilterOpt.getQuerySource()
926 || data.needsRefetch(selectedFilterOpt))
928 data = selectedFilterOpt.getQuerySource();
929 // rebuild the views completely, since prefs will also change
935 filterResultSet(selectedFilterOpt.getValue());
938 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
939 || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
941 mainFrame.setTitle(MessageManager
942 .getString("label.structure_chooser_manual_association"));
943 idInputAssSeqPanel.loadCmbAssSeq();
944 fileChooserAssSeqPanel.loadCmbAssSeq();
946 validateSelections();
950 * Validates user selection and enables the 'Add' and 'New View' buttons if
951 * all parameters are correct (the Add button will only be visible if there is
952 * at least one existing structure viewer open). This basically means at least
953 * one structure selected and no error messages.
955 * The 'Superpose Structures' option is enabled if either more than one
956 * structure is selected, or the 'Add' to existing view option is enabled, and
957 * disabled if the only option is to open a new view of a single structure.
960 protected void validateSelections()
962 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
964 btn_add.setEnabled(false);
965 String currentView = selectedFilterOpt.getView();
966 int selectedCount = 0;
967 if (currentView == VIEWS_FILTER)
969 selectedCount = getResultTable().getSelectedRows().length;
970 if (selectedCount > 0)
972 btn_add.setEnabled(true);
975 else if (currentView == VIEWS_LOCAL_PDB)
977 selectedCount = tbl_local_pdb.getSelectedRows().length;
978 if (selectedCount > 0)
980 btn_add.setEnabled(true);
983 else if (currentView == VIEWS_ENTER_ID)
985 validateAssociationEnterPdb();
987 else if (currentView == VIEWS_FROM_FILE)
989 validateAssociationFromFile();
992 btn_newView.setEnabled(btn_add.isEnabled());
995 * enable 'Superpose' option if more than one structure is selected,
996 * or there are view(s) available to add structure(s) to
999 .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
1003 protected boolean showPopupFor(int selectedRow, int x, int y)
1005 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1006 .getSelectedItem());
1007 String currentView = selectedFilterOpt.getView();
1009 if (currentView == VIEWS_FILTER
1010 && data instanceof ThreeDBStructureChooserQuerySource)
1013 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
1014 .getFTSDataFor(getResultTable(), selectedRow,
1015 discoveredStructuresSet);
1016 String pageUrl = row.getModelViewUrl();
1018 JPopupMenu popup = new JPopupMenu("3D Beacons");
1019 JMenuItem viewUrl = new JMenuItem("View model web page");
1020 if (pageUrl == null || "".equals(pageUrl.trim()))
1022 viewUrl.setEnabled(false);
1023 viewUrl.setText("No model page available.");
1025 viewUrl.addActionListener(new ActionListener()
1028 public void actionPerformed(ActionEvent e)
1030 Desktop.showUrl(pageUrl);
1034 SwingUtilities.invokeLater(new Runnable()
1039 popup.show(getResultTable(), x, y);
1044 // event not handled by us
1049 * Validates inputs from the Manual PDB entry panel
1051 protected void validateAssociationEnterPdb()
1053 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
1054 .getCmb_assSeq().getSelectedItem();
1055 lbl_pdbManualFetchStatus.setIcon(errorImage);
1056 lbl_pdbManualFetchStatus.setToolTipText("");
1057 if (txt_search.getText().length() > 0)
1059 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1060 MessageManager.formatMessage("info.no_pdb_entry_found_for",
1061 txt_search.getText())));
1064 if (errorWarning.length() > 0)
1066 lbl_pdbManualFetchStatus.setIcon(warningImage);
1067 lbl_pdbManualFetchStatus.setToolTipText(
1068 JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1071 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1072 .equalsIgnoreCase("-Select Associated Seq-"))
1074 txt_search.setEnabled(true);
1075 if (isValidPBDEntry)
1077 btn_add.setEnabled(true);
1078 lbl_pdbManualFetchStatus.setToolTipText("");
1079 lbl_pdbManualFetchStatus.setIcon(goodImage);
1084 txt_search.setEnabled(false);
1085 lbl_pdbManualFetchStatus.setIcon(errorImage);
1090 * Validates inputs for the manual PDB file selection options
1092 protected void validateAssociationFromFile()
1094 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1095 .getCmb_assSeq().getSelectedItem();
1096 // lbl_fromFileStatus.setIcon(errorImage);
1097 String pdbFileString = "";
1098 String pdbFileTooltip = "";
1099 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1100 .getName().equalsIgnoreCase("-Select Associated Seq-")))
1102 btn_pdbFromFile.setEnabled(true);
1103 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1105 btn_add.setEnabled(true);
1106 // lbl_fromFileStatus.setIcon(goodImage);
1107 pdbFileString = new File(selectedPdbFileName).getName();
1108 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1109 setPdbOptionsEnabled(true);
1113 pdbFileString = MessageManager.getString("label.none");
1114 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1115 setPdbOptionsEnabled(false);
1120 btn_pdbFromFile.setEnabled(false);
1121 setPdbOptionsEnabled(false);
1122 // lbl_fromFileStatus.setIcon(errorImage);
1123 pdbFileString = MessageManager.getString("label.none");
1124 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1126 lbl_pdbFile.setText(pdbFileString);
1127 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1130 String paeFileString = "";
1131 String paeFileTooltip = "";
1132 if (localPdbPaeMatrixFileName != null
1133 && localPdbPaeMatrixFileName.length() > 0)
1135 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1136 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1141 paeFileString = MessageManager.getString("label.none");
1142 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1144 lbl_paeFile.setText(paeFileString);
1145 lbl_paeFile.setToolTipText(paeFileTooltip);
1149 protected void cmbAssSeqStateChanged()
1151 validateSelections();
1154 private FilterOption lastSelected = null;
1157 * Handles the state change event for the 'filter' combo-box and 'invert'
1161 protected void stateChanged(ItemEvent e)
1163 if (e.getSource() instanceof JCheckBox)
1165 updateCurrentView();
1169 if (e.getStateChange() == ItemEvent.SELECTED)
1171 updateCurrentView();
1178 * select structures for viewing by their PDB IDs
1181 * @return true if structures were found and marked as selected
1183 public boolean selectStructure(String... pdbids)
1185 boolean found = false;
1187 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1188 .getSelectedItem());
1189 String currentView = selectedFilterOpt.getView();
1190 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1191 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1193 if (restable == null)
1195 // can't select (enter PDB ID, or load file - need to also select which
1196 // sequence to associate with)
1200 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1201 for (int r = 0; r < restable.getRowCount(); r++)
1203 for (int p = 0; p < pdbids.length; p++)
1205 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1206 .equalsIgnoreCase(pdbids[p]))
1208 restable.setRowSelectionInterval(r, r);
1217 * Handles the 'New View' action
1220 protected void newView_ActionPerformed()
1222 targetView.setSelectedItem(null);
1223 showStructures(false);
1227 * Handles the 'Add to existing viewer' action
1230 protected void add_ActionPerformed()
1232 showStructures(false);
1236 * structure viewer opened by this dialog, or null
1238 private StructureViewer sViewer = null;
1240 public void showStructures(boolean waitUntilFinished)
1243 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1245 final int preferredHeight = pnl_filter.getHeight();
1246 btn_add.setEnabled(false);
1247 btn_newView.setEnabled(false);
1248 btn_cancel.setEnabled(false);
1249 actionsPanel.setEnabled(false);
1251 final String progress = MessageManager
1252 .getString("label.working_ellipsis");
1253 setProgressBar(progress, progress.hashCode());
1254 Runnable viewStruc = new Runnable()
1259 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1260 .getSelectedItem());
1261 String currentView = selectedFilterOpt.getView();
1262 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1265 if (currentView == VIEWS_FILTER)
1267 int[] selectedRows = restable.getSelectedRows();
1268 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1269 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1270 pdbEntriesToView = data.collectSelectedRows(restable,
1271 selectedRows, selectedSeqsToView);
1273 SequenceI[] selectedSeqs = selectedSeqsToView
1274 .toArray(new SequenceI[selectedSeqsToView.size()]);
1275 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1278 else if (currentView == VIEWS_LOCAL_PDB)
1280 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1281 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1283 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1285 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1287 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1288 for (int row : selectedRows)
1290 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1291 .getModel()).getPDBEntryAt(row).getPdbEntry();
1293 pdbEntriesToView[count++] = pdbEntry;
1294 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1295 .getValueAt(row, refSeqColIndex);
1296 selectedSeqsToView.add(selectedSeq);
1298 SequenceI[] selectedSeqs = selectedSeqsToView
1299 .toArray(new SequenceI[selectedSeqsToView.size()]);
1300 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1303 else if (currentView == VIEWS_ENTER_ID)
1305 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1306 .getCmb_assSeq().getSelectedItem()).getSequence();
1307 if (userSelectedSeq != null)
1309 selectedSequence = userSelectedSeq;
1311 String pdbIdStr = txt_search.getText();
1312 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1313 if (pdbEntry == null)
1315 pdbEntry = new PDBEntry();
1316 if (pdbIdStr.split(":").length > 1)
1318 pdbEntry.setId(pdbIdStr.split(":")[0]);
1319 pdbEntry.setChainCode(
1320 pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1324 pdbEntry.setId(pdbIdStr);
1326 pdbEntry.setType(PDBEntry.Type.PDB);
1327 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1330 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1331 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1333 { selectedSequence });
1335 else if (currentView == VIEWS_FROM_FILE)
1337 StructureChooser sc = StructureChooser.this;
1338 TFType tft = (TFType) sc.combo_tempFacAs.getSelectedItem();
1339 String paeFilename = sc.localPdbPaeMatrixFileName;
1340 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1341 .getCmb_assSeq().getSelectedItem();
1342 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1343 if (userSelectedSeq != null)
1345 selectedSequence = userSelectedSeq;
1347 String pdbFilename = selectedPdbFileName;
1348 // TODO - tidy up this ugly hack so we call launchStructureViewer too
1349 StructureChooser.openStructureFileForSequence(ssm, sc, ap,
1350 selectedSequence, true, pdbFilename, tft, paeFilename,false,
1351 true,false,getTargetedStructureViewer(ssm).getViewerType());
1353 SwingUtilities.invokeLater(new Runnable()
1358 setProgressBar("Complete.", progress.hashCode());
1359 closeAction(preferredHeight);
1360 mainFrame.dispose();
1365 Thread runner = new Thread(viewStruc);
1367 if (waitUntilFinished)
1369 while (sViewer == null ? runner.isAlive()
1370 : (sViewer.sview == null ? true
1371 : !sViewer.sview.hasMapping()))
1376 } catch (InterruptedException ie)
1385 * Answers a structure viewer (new or existing) configured to superimpose
1386 * added structures or not according to the user's choice
1391 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1393 Object sv = targetView.getSelectedItem();
1395 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1399 * Adds PDB structures to a new or existing structure viewer
1402 * @param pdbEntriesToView
1407 private StructureViewer launchStructureViewer(
1408 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1409 final AlignmentPanel alignPanel, SequenceI[] sequences)
1411 return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
1415 private StructureViewer launchStructureViewer(
1416 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1417 final AlignmentPanel alignPanel, SequenceI[] sequences,
1418 ViewerType viewerType)
1420 long progressId = sequences.hashCode();
1421 setProgressBar(MessageManager
1422 .getString("status.launching_3d_structure_viewer"), progressId);
1423 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1424 boolean superimpose = chk_superpose.isSelected();
1425 theViewer.setSuperpose(superimpose);
1427 // if we're running in --headless mode make this viewer synchronous
1428 if (Jalview.isHeadlessMode())
1430 theViewer.setAsync(false);
1434 * remember user's choice of superimpose or not
1436 Cache.setProperty(AUTOSUPERIMPOSE,
1437 Boolean.valueOf(superimpose).toString());
1439 setProgressBar(null, progressId);
1440 if (SiftsSettings.isMapWithSifts())
1442 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1444 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1445 // real PDB ID. For moment, we can also safely do this if there is already
1446 // a known mapping between the PDBEntry and the sequence.
1447 for (SequenceI seq : sequences)
1449 PDBEntry pdbe = pdbEntriesToView[p++];
1450 if (pdbe != null && pdbe.getFile() != null)
1452 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1453 if (smm != null && smm.length > 0)
1455 for (StructureMapping sm : smm)
1457 if (sm.getSequence() == seq)
1464 if (seq.getPrimaryDBRefs().isEmpty())
1466 seqsWithoutSourceDBRef.add(seq);
1470 if (!seqsWithoutSourceDBRef.isEmpty())
1472 int y = seqsWithoutSourceDBRef.size();
1473 setProgressBar(MessageManager.formatMessage(
1474 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1476 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1477 .toArray(new SequenceI[y]);
1478 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1479 dbRefFetcher.fetchDBRefs(true);
1481 setProgressBar("Fetch complete.", progressId); // todo i18n
1484 if (pdbEntriesToView.length > 1)
1487 MessageManager.getString(
1488 "status.fetching_3d_structures_for_selected_entries"),
1490 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
1495 setProgressBar(MessageManager.formatMessage(
1496 "status.fetching_3d_structures_for",
1497 pdbEntriesToView[0].getId()), progressId);
1498 // Can we pass a pre-computeMappinged pdbFile?
1499 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel,
1502 setProgressBar(null, progressId);
1503 // remember the last viewer we used...
1504 lastTargetedView = theViewer;
1509 * Populates the combo-box used in associating manually fetched structures to
1510 * a unique sequence when more than one sequence selection is made.
1513 protected void populateCmbAssociateSeqOptions(
1514 JComboBox<AssociateSeqOptions> cmb_assSeq,
1515 JLabel lbl_associateSeq)
1517 cmb_assSeq.removeAllItems();
1519 new AssociateSeqOptions("-Select Associated Seq-", null));
1520 lbl_associateSeq.setVisible(false);
1521 if (selectedSequences.length > 1)
1523 for (SequenceI seq : selectedSequences)
1525 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1530 String seqName = selectedSequence.getDisplayId(false);
1531 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1532 lbl_associateSeq.setText(seqName);
1533 lbl_associateSeq.setVisible(true);
1534 cmb_assSeq.setVisible(false);
1538 protected boolean isStructuresDiscovered()
1540 return discoveredStructuresSet != null
1541 && !discoveredStructuresSet.isEmpty();
1544 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1546 // Doing a search for "1" or "1c" is valuable?
1547 // Those work but are enormously slow.
1550 protected void txt_search_ActionPerformed()
1552 String text = txt_search.getText().trim();
1553 if (text.length() >= PDB_ID_MIN)
1560 errorWarning.setLength(0);
1561 isValidPBDEntry = false;
1562 if (text.length() > 0)
1564 // TODO move this pdb id search into the PDB specific
1566 // for moment, it will work fine as is because it is self-contained
1567 String searchTerm = text.toLowerCase(Locale.ROOT);
1568 searchTerm = searchTerm.split(":")[0];
1569 // jalview.bin.Console.outPrintln(">>>>> search term : " +
1571 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1572 FTSRestRequest pdbRequest = new FTSRestRequest();
1573 pdbRequest.setAllowEmptySeq(false);
1574 pdbRequest.setResponseSize(1);
1575 pdbRequest.setFieldToSearchBy("(pdb_id:");
1576 pdbRequest.setWantedFields(wantedFields);
1577 pdbRequest.setSearchTerm(searchTerm + ")");
1578 pdbRequest.setAssociatedSequence(selectedSequence);
1579 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1580 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1581 FTSRestResponse resultList;
1584 resultList = pdbRestClient.executeRequest(pdbRequest);
1585 } catch (Exception e)
1587 errorWarning.append(e.getMessage());
1591 validateSelections();
1593 if (resultList.getSearchSummary() != null
1594 && resultList.getSearchSummary().size() > 0)
1596 isValidPBDEntry = true;
1599 validateSelections();
1605 protected void tabRefresh()
1607 if (selectedSequences != null)
1609 lbl_loading.setVisible(true);
1610 Thread refreshThread = new Thread(new Runnable()
1615 fetchStructuresMetaData();
1616 // populateFilterComboBox(true, cachedPDBExists);
1619 ((FilterOption) cmb_filterOption.getSelectedItem())
1621 lbl_loading.setVisible(false);
1624 refreshThread.start();
1628 public class PDBEntryTableModel extends AbstractTableModel
1630 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1633 private List<CachedPDB> pdbEntries;
1635 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1637 this.pdbEntries = new ArrayList<>(pdbEntries);
1641 public String getColumnName(int columnIndex)
1643 return columns[columnIndex];
1647 public int getRowCount()
1649 return pdbEntries.size();
1653 public int getColumnCount()
1655 return columns.length;
1659 public boolean isCellEditable(int row, int column)
1665 public Object getValueAt(int rowIndex, int columnIndex)
1667 Object value = "??";
1668 CachedPDB entry = pdbEntries.get(rowIndex);
1669 switch (columnIndex)
1672 value = entry.getSequence();
1675 value = entry.getQualifiedId();
1678 value = entry.getPdbEntry().getChainCode() == null ? "_"
1679 : entry.getPdbEntry().getChainCode();
1682 value = entry.getPdbEntry().getType();
1685 value = entry.getPdbEntry().getFile();
1692 public Class<?> getColumnClass(int columnIndex)
1694 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1697 public CachedPDB getPDBEntryAt(int row)
1699 return pdbEntries.get(row);
1704 private class CachedPDB
1706 private SequenceI sequence;
1708 private PDBEntry pdbEntry;
1710 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1712 this.sequence = sequence;
1713 this.pdbEntry = pdbEntry;
1716 public String getQualifiedId()
1718 if (pdbEntry.hasProvider())
1720 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1722 return pdbEntry.toString();
1725 public SequenceI getSequence()
1730 public PDBEntry getPdbEntry()
1737 private IProgressIndicator progressBar;
1740 public void setProgressBar(String message, long id)
1742 if (!Platform.isHeadless() && progressBar != null)
1743 progressBar.setProgressBar(message, id);
1747 public void registerHandler(long id, IProgressIndicatorHandler handler)
1749 if (progressBar != null)
1750 progressBar.registerHandler(id, handler);
1754 public boolean operationInProgress()
1756 return progressBar == null ? false : progressBar.operationInProgress();
1759 public JalviewStructureDisplayI getOpenedStructureViewer()
1761 return sViewer == null ? null : sViewer.sview;
1765 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1767 data.setDocFieldPrefs(newPrefs);
1773 * @return true when all initialisation threads have finished and dialog is
1776 public boolean isDialogVisible()
1778 return mainFrame != null && data != null && cmb_filterOption != null
1779 && mainFrame.isVisible()
1780 && cmb_filterOption.getSelectedItem() != null;
1785 * @return true if the 3D-Beacons query button will/has been displayed
1787 public boolean isCanQueryTDB()
1792 public boolean isNotQueriedTDBYet()
1794 return notQueriedTDBYet;
1798 * Open a single structure file for a given sequence
1800 public static void openStructureFileForSequence(
1801 StructureSelectionManager ssm, StructureChooser sc,
1802 AlignmentPanel ap, SequenceI seq, boolean prompt,
1803 String sFilename, TFType tft, String paeFilename,
1804 boolean doXferSettings)
1806 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1807 paeFilename, false, true, doXferSettings, null);
1819 * @param paeFilename
1820 * @param forceHeadless
1821 * @param showRefAnnotations
1822 * @param doXferSettings
1823 * @param viewerType - when not null means the viewer will be opened, providing forceHeadless/headless is not true
1826 public static StructureViewer openStructureFileForSequence(
1827 StructureSelectionManager ssm, StructureChooser sc,
1828 AlignmentPanel ap, SequenceI seq, boolean prompt,
1829 String sFilename, TFType tft, String paeFilename,
1830 boolean forceHeadless, boolean showRefAnnotations,
1831 boolean doXferSettings, ViewerType viewerType)
1833 StructureViewer sv = null;
1834 boolean headless = forceHeadless;
1839 // suppress structure viewer's external service queries
1840 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false,
1845 ssm = ap.getStructureSelectionManager();
1846 StructureSelectionManager.doConfigureStructurePrefs(ssm);
1849 PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1850 sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
1851 tft, paeFilename, doXferSettings);
1853 // if headless, "false" in the sc constructor above will avoid GUI behaviour
1854 // in sc.launchStructureViewer()
1855 if (!headless && !(viewerType == null))
1857 sv = sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1859 { seq }, viewerType);
1861 sv.getJalviewStructureDisplay().raiseViewer();
1864 sc.mainFrame.dispose();
1866 // TODO should honor preferences - only show reference annotation that is requested - JAL-4415 JAL-3124
1867 if (showRefAnnotations)
1869 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1875 public static void showReferenceAnnotationsForSequence(AlignFrame af,
1878 AlignViewport av = af.getCurrentView();
1879 AlignmentI al = av.getAlignment();
1881 List<SequenceI> forSequences = new ArrayList<>();
1882 forSequences.add(sequence);
1883 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1884 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1886 final SequenceGroup selectionGroup = av.getSelectionGroup();
1887 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1888 for (AlignmentViewPanel ap : af.getAlignPanels())
1890 // required to readjust the height and position of the PAE
1892 ap.adjustAnnotationHeight();
1898 public JProgressBar getProgressBar(long id)
1900 return progressBar.getProgressBar(id);