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.JTable;
44 import javax.swing.SwingUtilities;
45 import javax.swing.table.AbstractTableModel;
47 import com.stevesoft.pat.Regex;
49 import jalview.analysis.AlignmentUtils;
50 import jalview.api.AlignmentViewPanel;
51 import jalview.api.structures.JalviewStructureDisplayI;
52 import jalview.bin.Cache;
53 import jalview.bin.Console;
54 import jalview.bin.Jalview;
55 import jalview.datamodel.AlignmentAnnotation;
56 import jalview.datamodel.AlignmentI;
57 import jalview.datamodel.PDBEntry;
58 import jalview.datamodel.SequenceGroup;
59 import jalview.datamodel.SequenceI;
60 import jalview.ext.jmol.JmolParser;
61 import jalview.fts.api.FTSData;
62 import jalview.fts.api.FTSDataColumnI;
63 import jalview.fts.api.FTSRestClientI;
64 import jalview.fts.core.FTSDataColumnPreferences;
65 import jalview.fts.core.FTSRestRequest;
66 import jalview.fts.core.FTSRestResponse;
67 import jalview.fts.service.pdb.PDBFTSRestClient;
68 import jalview.fts.service.threedbeacons.TDB_FTSData;
69 import jalview.gui.StructureViewer.ViewerType;
70 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
71 import jalview.gui.structurechooser.StructureChooserQuerySource;
72 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
73 import jalview.io.DataSourceType;
74 import jalview.io.JalviewFileChooser;
75 import jalview.io.JalviewFileView;
76 import jalview.jbgui.FilterOption;
77 import jalview.jbgui.GStructureChooser;
78 import jalview.structure.StructureImportSettings.TFType;
79 import jalview.structure.StructureMapping;
80 import jalview.structure.StructureSelectionManager;
81 import jalview.util.IdUtils;
82 import jalview.util.IdUtils.IdType;
83 import jalview.util.MessageManager;
84 import jalview.util.Platform;
85 import jalview.util.StringUtils;
86 import jalview.ws.DBRefFetcher;
87 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
88 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
89 import jalview.ws.seqfetcher.DbSourceProxy;
90 import jalview.ws.sifts.SiftsSettings;
93 * Provides the behaviors for the Structure chooser Panel
98 @SuppressWarnings("serial")
99 public class StructureChooser extends GStructureChooser
100 implements IProgressIndicator
102 private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
105 * warn user if need to fetch more than this many uniprot records at once
107 private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
109 private SequenceI selectedSequence;
111 private SequenceI[] selectedSequences;
113 private IProgressIndicator progressIndicator;
115 private Collection<FTSData> discoveredStructuresSet;
117 private StructureChooserQuerySource data;
120 protected FTSDataColumnPreferences getFTSDocFieldPrefs()
122 return data.getDocFieldPrefs();
125 private String selectedPdbFileName;
127 private TFType localPdbTempfacType;
129 private String localPdbPaeMatrixFileName;
131 private boolean isValidPBDEntry;
133 private boolean cachedPDBExists;
135 private Collection<FTSData> lastDiscoveredStructuresSet;
137 private boolean canQueryTDB = false;
139 private boolean notQueriedTDBYet = true;
141 List<SequenceI> seqsWithoutSourceDBRef = null;
143 private boolean showChooserGUI = true;
146 * when true, queries to external services are supressed (no SIFTs, no PDBe,
147 * no 3D-Beacons, etc)
149 private boolean dontQueryServices = false;
151 private static StructureViewer lastTargetedView = null;
153 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
156 this(selectedSeqs, selectedSeq, ap, true);
159 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
160 AlignmentPanel ap, boolean showGUI)
162 this(selectedSeqs, selectedSeq, ap, showGUI, false);
165 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
166 AlignmentPanel ap, boolean showGUI, boolean dontQueryServices)
169 // which FTS engine to use
170 data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
174 this.selectedSequence = selectedSeq;
175 this.selectedSequences = selectedSeqs;
176 this.progressIndicator = (ap == null) ? null : ap.alignFrame;
177 this.showChooserGUI = showGUI;
178 this.dontQueryServices = dontQueryServices;
184 * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
185 * least one structure are discovered.
187 private void populateSeqsWithoutSourceDBRef()
189 seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
190 boolean needCanonical = false;
191 for (SequenceI seq : selectedSequences)
195 int dbRef = ThreeDBStructureChooserQuerySource
196 .checkUniprotRefs(seq.getDBRefs());
201 // need to retrieve canonicals
202 needCanonical = true;
203 seqsWithoutSourceDBRef.add(seq);
207 // could be a sequence with pdb ref
208 if (seq.getAllPDBEntries() == null
209 || seq.getAllPDBEntries().size() == 0)
211 seqsWithoutSourceDBRef.add(seq);
217 // retrieve database refs for protein sequences
218 if (!seqsWithoutSourceDBRef.isEmpty())
223 // triggers display of the 'Query TDB' button
224 notQueriedTDBYet = true;
230 * Initializes parameters used by the Structure Chooser Panel
232 protected void init()
234 if (!Jalview.isHeadlessMode())
236 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
239 chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
240 btn_queryTDB.addActionListener(new ActionListener()
244 public void actionPerformed(ActionEvent e)
246 promptForTDBFetch(false);
250 if (!dontQueryServices)
252 Executors.defaultThreadFactory().newThread(new Runnable()
257 populateSeqsWithoutSourceDBRef();
258 initialStructureDiscovery();
266 "Structure chooser not querying services to discover metadata.");
271 private void initialStructureDiscovery()
273 // check which FTS engine to use
274 data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
276 // ensure a filter option is in force for search
277 populateFilterComboBox(true, cachedPDBExists);
279 // looks for any existing structures already loaded
280 // for the sequences (the cached ones)
281 // then queries the StructureChooserQuerySource to
282 // discover more structures.
284 // Possible optimisation is to only begin querying
285 // the structure chooser if there are no cached structures.
287 long startTime = System.currentTimeMillis();
288 updateProgressIndicator(
289 MessageManager.getString("status.loading_cached_pdb_entries"),
291 loadLocalCachedPDBEntries();
292 updateProgressIndicator(null, startTime);
293 updateProgressIndicator(
294 MessageManager.getString("status.searching_for_pdb_structures"),
296 fetchStructuresMetaData();
297 // revise filter options if no results were found
298 populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
299 discoverStructureViews();
300 updateProgressIndicator(null, startTime);
301 mainFrame.setVisible(showChooserGUI);
306 * raises dialog for Uniprot fetch followed by 3D beacons search
309 * - when true, don't ask, just fetch
311 public void promptForTDBFetch(boolean ignoreGui)
313 final long progressId = IdUtils.newId(IdType.PROGRESS);
315 // final action after prompting and discovering db refs
316 final Runnable strucDiscovery = new Runnable()
321 mainFrame.setEnabled(false);
322 cmb_filterOption.setEnabled(false);
323 progressBar.setProgressBar(
324 MessageManager.getString("status.searching_3d_beacons"),
326 btn_queryTDB.setEnabled(false);
327 // TODO: warn if no accessions discovered
328 populateSeqsWithoutSourceDBRef();
329 // redo initial discovery - this time with 3d beacons
331 previousWantedFields = null;
332 lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
333 cmb_filterOption.setSelectedItem(null);
334 cachedPDBExists = false; // reset to initial
335 initialStructureDiscovery();
336 if (!isStructuresDiscovered())
338 progressBar.setProgressBar(MessageManager.getString(
339 "status.no_structures_discovered_from_3d_beacons"),
341 btn_queryTDB.setToolTipText(MessageManager.getString(
342 "status.no_structures_discovered_from_3d_beacons"));
343 btn_queryTDB.setEnabled(false);
344 pnl_queryTDB.setVisible(false);
348 cmb_filterOption.setSelectedIndex(0); // select 'best'
349 btn_queryTDB.setVisible(false);
350 pnl_queryTDB.setVisible(false);
351 progressBar.setProgressBar(null, progressId);
353 mainFrame.setEnabled(true);
354 cmb_filterOption.setEnabled(true);
358 final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
362 public void finished()
364 // filter has been selected, so we set flag to remove ourselves
365 notQueriedTDBYet = false;
366 // new thread to discover structures - via 3d beacons
367 Executors.defaultThreadFactory().newThread(strucDiscovery).start();
372 // fetch db refs if OK pressed
373 final Runnable discoverCanonicalDBrefs = () -> {
374 btn_queryTDB.setEnabled(false);
375 populateSeqsWithoutSourceDBRef();
377 final int y = seqsWithoutSourceDBRef.size();
380 final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
381 .toArray(new SequenceI[y]);
382 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
383 progressBar, new DbSourceProxy[]
384 { new jalview.ws.dbsources.Uniprot() }, null, false);
385 dbRefFetcher.addListener(afterDbRefFetch);
386 // ideally this would also gracefully run with callbacks
388 dbRefFetcher.fetchDBRefs(true);
392 // call finished action directly
393 afterDbRefFetch.finished();
396 final Runnable revertview = () -> {
397 if (lastSelected != null)
399 cmb_filterOption.setSelectedItem(lastSelected);
402 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
403 THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
404 Console.debug("Using Uniprot fetch threshold of " + threshold);
405 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
407 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
410 // need cancel and no to result in the discoverPDB action - mocked is
411 // 'cancel' TODO: mock should be OK
413 StructureChooser thisSC = this;
414 JvOptionPane.newOptionDialog(thisSC.getFrame())
415 .setResponseHandler(JvOptionPane.OK_OPTION,
416 discoverCanonicalDBrefs)
417 .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
418 .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
420 MessageManager.formatMessage(
421 "label.fetch_references_for_3dbeacons",
422 seqsWithoutSourceDBRef.size()),
423 MessageManager.getString("label.3dbeacons"),
424 JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
426 { MessageManager.getString("action.ok"),
427 MessageManager.getString("action.cancel") },
428 MessageManager.getString("action.ok"), false);
432 * Builds a drop-down choice list of existing structure viewers to which new
433 * structures may be added. If this list is empty then it, and the 'Add'
434 * button, are hidden.
436 private void discoverStructureViews()
438 if (Desktop.instance != null)
440 targetView.removeAllItems();
441 if (lastTargetedView != null && !lastTargetedView.isVisible())
443 lastTargetedView = null;
445 int linkedViewsAt = 0;
446 for (StructureViewerBase view : Desktop.instance
447 .getStructureViewers(null, null))
449 StructureViewer viewHandler = (lastTargetedView != null
450 && lastTargetedView.sview == view) ? lastTargetedView
451 : StructureViewer.reconfigure(view);
453 if (view.isLinkedWith(ap))
455 targetView.insertItemAt(viewHandler, linkedViewsAt++);
459 targetView.addItem(viewHandler);
464 * show option to Add to viewer if at least 1 viewer found
466 targetView.setVisible(false);
467 if (targetView.getItemCount() > 0)
469 targetView.setVisible(true);
470 if (lastTargetedView != null)
472 targetView.setSelectedItem(lastTargetedView);
476 targetView.setSelectedIndex(0);
479 btn_add.setVisible(targetView.isVisible());
484 * Updates the progress indicator with the specified message
487 * displayed message for the operation
489 * unique handle for this indicator
491 protected void updateProgressIndicator(String message, long id)
493 if (progressIndicator != null)
495 progressIndicator.setProgressBar(message, id);
500 * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
503 void fetchStructuresMetaData()
505 long startTime = System.currentTimeMillis();
506 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
507 .getStructureSummaryFields();
509 discoveredStructuresSet = new LinkedHashSet<>();
510 HashSet<String> errors = new HashSet<>();
512 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
515 for (SequenceI seq : selectedSequences)
518 FTSRestResponse resultList;
521 resultList = data.fetchStructuresMetaData(seq, wantedFields,
522 selectedFilterOpt, !chk_invertFilter.isSelected());
523 // null response means the FTSengine didn't yield a query for this
524 // consider designing a special exception if we really wanted to be
526 if (resultList == null)
530 } catch (Exception e)
532 Console.printStackTrace(e);
533 errors.add(e.getMessage());
536 if (resultList.getSearchSummary() != null
537 && !resultList.getSearchSummary().isEmpty())
539 discoveredStructuresSet.addAll(resultList.getSearchSummary());
543 int noOfStructuresFound = 0;
544 String totalTime = (System.currentTimeMillis() - startTime)
546 if (discoveredStructuresSet != null
547 && !discoveredStructuresSet.isEmpty())
550 .setModel(data.getTableModel(discoveredStructuresSet));
552 noOfStructuresFound = discoveredStructuresSet.size();
553 lastDiscoveredStructuresSet = discoveredStructuresSet;
554 mainFrame.setTitle(MessageManager.formatMessage(
555 "label.structure_chooser_no_of_structures",
556 noOfStructuresFound, totalTime));
560 mainFrame.setTitle(MessageManager
561 .getString("label.structure_chooser_manual_association"));
562 if (errors.size() > 0)
564 StringBuilder errorMsg = new StringBuilder();
565 for (String error : errors)
567 errorMsg.append(error).append("\n");
569 if (!Jalview.isHeadlessMode())
571 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
572 MessageManager.getString("label.pdb_web-service_error"),
573 JvOptionPane.ERROR_MESSAGE);
578 MessageManager.getString("label.pdb_web-service_error"));
579 Console.debug(errorMsg.toString());
585 protected void loadLocalCachedPDBEntries()
587 ArrayList<CachedPDB> entries = new ArrayList<>();
588 for (SequenceI seq : selectedSequences)
590 if (seq.getDatasetSequence() != null
591 && seq.getDatasetSequence().getAllPDBEntries() != null)
593 for (PDBEntry pdbEntry : seq.getDatasetSequence()
596 if (pdbEntry.getFile() != null)
598 entries.add(new CachedPDB(seq, pdbEntry));
603 cachedPDBExists = !entries.isEmpty();
604 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
605 tbl_local_pdb.setModel(tableModelx);
609 * Filters a given list of discovered structures based on supplied argument
611 * @param fieldToFilterBy
612 * the field to filter by
614 void filterResultSet(final String fieldToFilterBy)
616 Thread filterThread = new Thread(new Runnable()
622 long startTime = System.currentTimeMillis();
623 lbl_loading.setVisible(true);
624 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
625 .getStructureSummaryFields();
626 Collection<FTSData> filteredResponse = new HashSet<>();
627 HashSet<String> errors = new HashSet<>();
629 for (SequenceI seq : selectedSequences)
632 FTSRestResponse resultList;
635 resultList = data.selectFirstRankedQuery(seq,
636 discoveredStructuresSet, wantedFields, fieldToFilterBy,
637 !chk_invertFilter.isSelected());
639 } catch (Exception e)
641 Console.debugPrintStackTrace(e);
642 errors.add(e.getMessage());
645 if (resultList.getSearchSummary() != null
646 && !resultList.getSearchSummary().isEmpty())
648 filteredResponse.addAll(resultList.getSearchSummary());
652 String totalTime = (System.currentTimeMillis() - startTime)
654 if (!filteredResponse.isEmpty())
656 final int filterResponseCount = filteredResponse.size();
657 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
658 reorderedStructuresSet.addAll(filteredResponse);
659 reorderedStructuresSet.addAll(discoveredStructuresSet);
661 .setModel(data.getTableModel(reorderedStructuresSet));
663 FTSRestResponse.configureTableColumn(getResultTable(),
664 wantedFields, tempUserPrefs);
665 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
666 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
667 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
668 // Update table selection model here
669 getResultTable().addRowSelectionInterval(0,
670 filterResponseCount - 1);
671 mainFrame.setTitle(MessageManager.formatMessage(
672 "label.structure_chooser_filter_time", totalTime));
676 mainFrame.setTitle(MessageManager.formatMessage(
677 "label.structure_chooser_filter_time", totalTime));
678 if (errors.size() > 0)
680 StringBuilder errorMsg = new StringBuilder();
681 for (String error : errors)
683 errorMsg.append(error).append("\n");
685 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
686 MessageManager.getString("label.pdb_web-service_error"),
687 JvOptionPane.ERROR_MESSAGE);
691 lbl_loading.setVisible(false);
693 validateSelections();
696 filterThread.start();
700 * Handles action event for btn_pdbFromFile
703 protected void pdbFromFile_actionPerformed()
705 // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
708 JalviewFileChooser chooser = new JalviewFileChooser(
709 Cache.getProperty("LAST_DIRECTORY"));
710 chooser.setFileView(new JalviewFileView());
711 chooser.setDialogTitle(
712 MessageManager.formatMessage("label.select_pdb_file_for",
713 selectedSequence.getDisplayId(false)));
714 chooser.setToolTipText(MessageManager.formatMessage(
715 "label.load_pdb_file_associate_with_sequence",
716 selectedSequence.getDisplayId(false)));
718 int value = chooser.showOpenDialog(null);
719 if (value == JalviewFileChooser.APPROVE_OPTION)
721 selectedPdbFileName = chooser.getSelectedFile().getPath();
722 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
723 boolean guessTFType = localPdbPaeMatrixFileName == null;
724 localPdbPaeMatrixFileName = guessPAEFilename();
725 guessTFType |= localPdbPaeMatrixFileName != null;
726 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
728 && alphaFold.search(new File(selectedPdbFileName).getName())
729 && !tempFacAsChanged)
731 // localPdbPaeMatrixFileName was null and now isn't and filename could
732 // well be AlphaFold and user hasn't adjusted the tempFacType
733 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
735 validateSelections();
740 * Handles action event for btn_paeMatrixFile
743 protected void paeMatrixFile_actionPerformed()
745 File pdbFile = new File(selectedPdbFileName);
746 String setFile = Cache.getProperty("LAST_DIRECTORY");
747 if (localPdbPaeMatrixFileName != null)
749 File paeFile = new File(localPdbPaeMatrixFileName);
750 if (paeFile.exists())
751 setFile = paeFile.getAbsolutePath();
752 else if (paeFile.getParentFile().exists())
753 setFile = paeFile.getParentFile().getAbsolutePath();
757 String guess = guessPAEFilename();
761 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
762 chooser.setFileView(new JalviewFileView());
763 chooser.setDialogTitle(MessageManager.formatMessage(
764 "label.select_pae_matrix_file_for", pdbFile.getName()));
765 chooser.setToolTipText(MessageManager.formatMessage(
766 "label.load_pae_matrix_file_associate_with_structure",
769 // TODO convert to Callable/Promise
770 int value = chooser.showOpenDialog(null);
771 if (value == JalviewFileChooser.APPROVE_OPTION)
773 String fileName = chooser.getSelectedFile().getPath();
776 PAEContactMatrix.validateContactMatrixFile(fileName);
777 } catch (Exception thr)
779 JvOptionPane.showInternalMessageDialog(this, MessageManager
780 .formatMessage("label.couldnt_load_file", new Object[]
781 { fileName }) + "<br>" + thr.getLocalizedMessage(),
782 MessageManager.getString("label.error_loading_file"),
783 JvOptionPane.WARNING_MESSAGE);
784 Console.error("Couldn't import " + fileName + " as a PAE matrix",
788 localPdbPaeMatrixFileName = fileName;
789 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
791 validateAssociationFromFile();
794 private String guessPAEFilename()
796 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
797 || selectedPdbFileName.toLowerCase(Locale.ROOT)
800 String jsonExt = selectedPdbFileName.substring(0,
801 selectedPdbFileName.length() - 4) + ".json";
802 // AlphaFold naming scheme
803 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
804 "predicted_aligned_error");
805 // nf-core mode naming scheme
806 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
808 if (new File(guessFile1).exists())
812 else if (new File(jsonExt).exists())
816 else if (new File(guessFile2).exists())
825 * Populates the filter combo-box options dynamically depending on discovered
828 protected void populateFilterComboBox(boolean haveData,
829 boolean cachedPDBExist)
831 populateFilterComboBox(haveData, cachedPDBExist, null);
835 * Populates the filter combo-box options dynamically depending on discovered
838 protected void populateFilterComboBox(boolean haveData,
839 boolean cachedPDBExist, FilterOption lastSel)
843 * temporarily suspend the change listener behaviour
845 cmb_filterOption.removeItemListener(this);
847 cmb_filterOption.removeAllItems();
850 List<FilterOption> filters = data
851 .getAvailableFilterOptions(VIEWS_FILTER);
852 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
853 lastDiscoveredStructuresSet);
855 for (FilterOption filter : filters)
857 if (lastSel != null && filter.equals(lastSel))
862 cmb_filterOption.addItem(filter);
866 cmb_filterOption.addItem(
867 new FilterOption(MessageManager.getString("label.enter_pdb_id"),
868 "-", VIEWS_ENTER_ID, false, null));
869 cmb_filterOption.addItem(
870 new FilterOption(MessageManager.getString("label.from_file"),
871 "-", VIEWS_FROM_FILE, false, null));
872 if (canQueryTDB && notQueriedTDBYet)
874 btn_queryTDB.setVisible(true);
875 pnl_queryTDB.setVisible(true);
880 FilterOption cachedOption = new FilterOption(
881 MessageManager.getString("label.cached_structures"), "-",
882 VIEWS_LOCAL_PDB, false, null);
883 cmb_filterOption.addItem(cachedOption);
886 cmb_filterOption.setSelectedItem(cachedOption);
891 cmb_filterOption.setSelectedIndex(selSet);
893 cmb_filterOption.addItemListener(this);
897 * Updates the displayed view based on the selected filter option
899 protected void updateCurrentView()
901 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
904 if (lastSelected == selectedFilterOpt)
906 // don't need to do anything, probably
909 // otherwise, record selection
910 // and update the layout and dialog accordingly
911 lastSelected = selectedFilterOpt;
913 layout_switchableViews.show(pnl_switchableViews,
914 selectedFilterOpt.getView());
915 String filterTitle = mainFrame.getTitle();
916 mainFrame.setTitle(frameTitle);
917 chk_invertFilter.setVisible(false);
919 if (selectedFilterOpt.getView() == VIEWS_FILTER)
921 mainFrame.setTitle(filterTitle);
922 // TDB Query has no invert as yet
923 chk_invertFilter.setVisible(selectedFilterOpt
924 .getQuerySource() instanceof PDBStructureChooserQuerySource);
926 if (data != selectedFilterOpt.getQuerySource()
927 || data.needsRefetch(selectedFilterOpt))
929 data = selectedFilterOpt.getQuerySource();
930 // rebuild the views completely, since prefs will also change
936 filterResultSet(selectedFilterOpt.getValue());
939 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
940 || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
942 mainFrame.setTitle(MessageManager
943 .getString("label.structure_chooser_manual_association"));
944 idInputAssSeqPanel.loadCmbAssSeq();
945 fileChooserAssSeqPanel.loadCmbAssSeq();
947 validateSelections();
951 * Validates user selection and enables the 'Add' and 'New View' buttons if
952 * all parameters are correct (the Add button will only be visible if there is
953 * at least one existing structure viewer open). This basically means at least
954 * one structure selected and no error messages.
956 * The 'Superpose Structures' option is enabled if either more than one
957 * structure is selected, or the 'Add' to existing view option is enabled, and
958 * disabled if the only option is to open a new view of a single structure.
961 protected void validateSelections()
963 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
965 btn_add.setEnabled(false);
966 String currentView = selectedFilterOpt.getView();
967 int selectedCount = 0;
968 if (currentView == VIEWS_FILTER)
970 selectedCount = getResultTable().getSelectedRows().length;
971 if (selectedCount > 0)
973 btn_add.setEnabled(true);
976 else if (currentView == VIEWS_LOCAL_PDB)
978 selectedCount = tbl_local_pdb.getSelectedRows().length;
979 if (selectedCount > 0)
981 btn_add.setEnabled(true);
984 else if (currentView == VIEWS_ENTER_ID)
986 validateAssociationEnterPdb();
988 else if (currentView == VIEWS_FROM_FILE)
990 validateAssociationFromFile();
993 btn_newView.setEnabled(btn_add.isEnabled());
996 * enable 'Superpose' option if more than one structure is selected,
997 * or there are view(s) available to add structure(s) to
1000 .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
1004 protected boolean showPopupFor(int selectedRow, int x, int y)
1006 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1007 .getSelectedItem());
1008 String currentView = selectedFilterOpt.getView();
1010 if (currentView == VIEWS_FILTER
1011 && data instanceof ThreeDBStructureChooserQuerySource)
1014 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
1015 .getFTSDataFor(getResultTable(), selectedRow,
1016 discoveredStructuresSet);
1017 String pageUrl = row.getModelViewUrl();
1019 JPopupMenu popup = new JPopupMenu("3D Beacons");
1020 JMenuItem viewUrl = new JMenuItem("View model web page");
1021 if (pageUrl == null || "".equals(pageUrl.trim()))
1023 viewUrl.setEnabled(false);
1024 viewUrl.setText("No model page available.");
1026 viewUrl.addActionListener(new ActionListener()
1029 public void actionPerformed(ActionEvent e)
1031 Desktop.showUrl(pageUrl);
1035 SwingUtilities.invokeLater(new Runnable()
1040 popup.show(getResultTable(), x, y);
1045 // event not handled by us
1050 * Validates inputs from the Manual PDB entry panel
1052 protected void validateAssociationEnterPdb()
1054 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
1055 .getCmb_assSeq().getSelectedItem();
1056 lbl_pdbManualFetchStatus.setIcon(errorImage);
1057 lbl_pdbManualFetchStatus.setToolTipText("");
1058 if (txt_search.getText().length() > 0)
1060 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1061 MessageManager.formatMessage("info.no_pdb_entry_found_for",
1062 txt_search.getText())));
1065 if (errorWarning.length() > 0)
1067 lbl_pdbManualFetchStatus.setIcon(warningImage);
1068 lbl_pdbManualFetchStatus.setToolTipText(
1069 JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1072 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1073 .equalsIgnoreCase("-Select Associated Seq-"))
1075 txt_search.setEnabled(true);
1076 if (isValidPBDEntry)
1078 btn_add.setEnabled(true);
1079 lbl_pdbManualFetchStatus.setToolTipText("");
1080 lbl_pdbManualFetchStatus.setIcon(goodImage);
1085 txt_search.setEnabled(false);
1086 lbl_pdbManualFetchStatus.setIcon(errorImage);
1091 * Validates inputs for the manual PDB file selection options
1093 protected void validateAssociationFromFile()
1095 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1096 .getCmb_assSeq().getSelectedItem();
1097 // lbl_fromFileStatus.setIcon(errorImage);
1098 String pdbFileString = "";
1099 String pdbFileTooltip = "";
1100 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1101 .getName().equalsIgnoreCase("-Select Associated Seq-")))
1103 btn_pdbFromFile.setEnabled(true);
1104 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1106 btn_add.setEnabled(true);
1107 // lbl_fromFileStatus.setIcon(goodImage);
1108 pdbFileString = new File(selectedPdbFileName).getName();
1109 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1110 setPdbOptionsEnabled(true);
1114 pdbFileString = MessageManager.getString("label.none");
1115 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1116 setPdbOptionsEnabled(false);
1121 btn_pdbFromFile.setEnabled(false);
1122 setPdbOptionsEnabled(false);
1123 // lbl_fromFileStatus.setIcon(errorImage);
1124 pdbFileString = MessageManager.getString("label.none");
1125 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1127 lbl_pdbFile.setText(pdbFileString);
1128 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1131 String paeFileString = "";
1132 String paeFileTooltip = "";
1133 if (localPdbPaeMatrixFileName != null
1134 && localPdbPaeMatrixFileName.length() > 0)
1136 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1137 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1142 paeFileString = MessageManager.getString("label.none");
1143 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1145 lbl_paeFile.setText(paeFileString);
1146 lbl_paeFile.setToolTipText(paeFileTooltip);
1150 protected void cmbAssSeqStateChanged()
1152 validateSelections();
1155 private FilterOption lastSelected = null;
1158 * Handles the state change event for the 'filter' combo-box and 'invert'
1162 protected void stateChanged(ItemEvent e)
1164 if (e.getSource() instanceof JCheckBox)
1166 updateCurrentView();
1170 if (e.getStateChange() == ItemEvent.SELECTED)
1172 updateCurrentView();
1179 * select structures for viewing by their PDB IDs
1182 * @return true if structures were found and marked as selected
1184 public boolean selectStructure(String... pdbids)
1186 boolean found = false;
1188 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1189 .getSelectedItem());
1190 String currentView = selectedFilterOpt.getView();
1191 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1192 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1194 if (restable == null)
1196 // can't select (enter PDB ID, or load file - need to also select which
1197 // sequence to associate with)
1201 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1202 for (int r = 0; r < restable.getRowCount(); r++)
1204 for (int p = 0; p < pdbids.length; p++)
1206 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1207 .equalsIgnoreCase(pdbids[p]))
1209 restable.setRowSelectionInterval(r, r);
1218 * Handles the 'New View' action
1221 protected void newView_ActionPerformed()
1223 targetView.setSelectedItem(null);
1224 showStructures(false);
1228 * Handles the 'Add to existing viewer' action
1231 protected void add_ActionPerformed()
1233 showStructures(false);
1237 * structure viewer opened by this dialog, or null
1239 private StructureViewer sViewer = null;
1241 public void showStructures(boolean waitUntilFinished)
1244 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1246 final int preferredHeight = pnl_filter.getHeight();
1247 btn_add.setEnabled(false);
1248 btn_newView.setEnabled(false);
1249 btn_cancel.setEnabled(false);
1250 actionsPanel.setEnabled(false);
1252 final String progress = MessageManager
1253 .getString("label.working_ellipsis");
1254 setProgressBar(progress, IdUtils.newId(IdType.PROGRESS, progress));
1255 Runnable viewStruc = new Runnable()
1260 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1261 .getSelectedItem());
1262 String currentView = selectedFilterOpt.getView();
1263 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1266 if (currentView == VIEWS_FILTER)
1268 int[] selectedRows = restable.getSelectedRows();
1269 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1270 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1271 pdbEntriesToView = data.collectSelectedRows(restable,
1272 selectedRows, selectedSeqsToView);
1274 SequenceI[] selectedSeqs = selectedSeqsToView
1275 .toArray(new SequenceI[selectedSeqsToView.size()]);
1276 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1279 else if (currentView == VIEWS_LOCAL_PDB)
1281 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1282 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1284 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1286 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1288 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1289 for (int row : selectedRows)
1291 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1292 .getModel()).getPDBEntryAt(row).getPdbEntry();
1294 pdbEntriesToView[count++] = pdbEntry;
1295 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1296 .getValueAt(row, refSeqColIndex);
1297 selectedSeqsToView.add(selectedSeq);
1299 SequenceI[] selectedSeqs = selectedSeqsToView
1300 .toArray(new SequenceI[selectedSeqsToView.size()]);
1301 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1304 else if (currentView == VIEWS_ENTER_ID)
1306 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1307 .getCmb_assSeq().getSelectedItem()).getSequence();
1308 if (userSelectedSeq != null)
1310 selectedSequence = userSelectedSeq;
1312 String pdbIdStr = txt_search.getText();
1313 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1314 if (pdbEntry == null)
1316 pdbEntry = new PDBEntry();
1317 if (pdbIdStr.split(":").length > 1)
1319 pdbEntry.setId(pdbIdStr.split(":")[0]);
1320 pdbEntry.setChainCode(
1321 pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1325 pdbEntry.setId(pdbIdStr);
1327 pdbEntry.setType(PDBEntry.Type.PDB);
1328 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1331 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1332 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1334 { selectedSequence });
1336 else if (currentView == VIEWS_FROM_FILE)
1338 StructureChooser sc = StructureChooser.this;
1339 TFType tft = (TFType) sc.combo_tempFacAs.getSelectedItem();
1340 String paeFilename = sc.localPdbPaeMatrixFileName;
1341 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1342 .getCmb_assSeq().getSelectedItem();
1343 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1344 if (userSelectedSeq != null)
1346 selectedSequence = userSelectedSeq;
1348 String pdbFilename = selectedPdbFileName;
1350 StructureChooser.openStructureFileForSequence(ssm, sc, ap,
1351 selectedSequence, true, pdbFilename, tft, paeFilename,
1354 SwingUtilities.invokeLater(new Runnable()
1359 setProgressBar("Complete.",
1360 IdUtils.newId(IdType.PROGRESS, progress));
1361 closeAction(preferredHeight);
1362 mainFrame.dispose();
1367 Thread runner = new Thread(viewStruc);
1369 if (waitUntilFinished)
1371 while (sViewer == null ? runner.isAlive()
1372 : (sViewer.sview == null ? true
1373 : !sViewer.sview.hasMapping()))
1378 } catch (InterruptedException ie)
1387 * Answers a structure viewer (new or existing) configured to superimpose
1388 * added structures or not according to the user's choice
1393 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1395 Object sv = targetView.getSelectedItem();
1397 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1401 * Adds PDB structures to a new or existing structure viewer
1404 * @param pdbEntriesToView
1409 private StructureViewer launchStructureViewer(
1410 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1411 final AlignmentPanel alignPanel, SequenceI[] sequences)
1413 return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
1417 private StructureViewer launchStructureViewer(
1418 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1419 final AlignmentPanel alignPanel, SequenceI[] sequences,
1420 ViewerType viewerType)
1422 long progressId = sequences.hashCode();
1423 setProgressBar(MessageManager
1424 .getString("status.launching_3d_structure_viewer"), progressId);
1425 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1426 boolean superimpose = chk_superpose.isSelected();
1427 theViewer.setSuperpose(superimpose);
1429 // if we're running in --headless mode make this viewer synchronous
1430 if (Jalview.isHeadlessMode())
1432 theViewer.setAsync(false);
1436 * remember user's choice of superimpose or not
1438 Cache.setProperty(AUTOSUPERIMPOSE,
1439 Boolean.valueOf(superimpose).toString());
1441 setProgressBar(null, progressId);
1442 if (SiftsSettings.isMapWithSifts())
1444 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1446 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1447 // real PDB ID. For moment, we can also safely do this if there is already
1448 // a known mapping between the PDBEntry and the sequence.
1449 for (SequenceI seq : sequences)
1451 PDBEntry pdbe = pdbEntriesToView[p++];
1452 if (pdbe != null && pdbe.getFile() != null)
1454 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1455 if (smm != null && smm.length > 0)
1457 for (StructureMapping sm : smm)
1459 if (sm.getSequence() == seq)
1466 if (seq.getPrimaryDBRefs().isEmpty())
1468 seqsWithoutSourceDBRef.add(seq);
1472 if (!seqsWithoutSourceDBRef.isEmpty())
1474 int y = seqsWithoutSourceDBRef.size();
1475 setProgressBar(MessageManager.formatMessage(
1476 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1478 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1479 .toArray(new SequenceI[y]);
1480 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1481 dbRefFetcher.fetchDBRefs(true);
1483 setProgressBar("Fetch complete.", progressId); // todo i18n
1486 if (pdbEntriesToView.length > 1)
1489 MessageManager.getString(
1490 "status.fetching_3d_structures_for_selected_entries"),
1492 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
1497 setProgressBar(MessageManager.formatMessage(
1498 "status.fetching_3d_structures_for",
1499 pdbEntriesToView[0].getId()), progressId);
1500 // Can we pass a pre-computeMappinged pdbFile?
1501 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel,
1504 setProgressBar(null, progressId);
1505 // remember the last viewer we used...
1506 lastTargetedView = theViewer;
1511 * Populates the combo-box used in associating manually fetched structures to
1512 * a unique sequence when more than one sequence selection is made.
1515 protected void populateCmbAssociateSeqOptions(
1516 JComboBox<AssociateSeqOptions> cmb_assSeq,
1517 JLabel lbl_associateSeq)
1519 cmb_assSeq.removeAllItems();
1521 new AssociateSeqOptions("-Select Associated Seq-", null));
1522 lbl_associateSeq.setVisible(false);
1523 if (selectedSequences.length > 1)
1525 for (SequenceI seq : selectedSequences)
1527 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1532 String seqName = selectedSequence.getDisplayId(false);
1533 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1534 lbl_associateSeq.setText(seqName);
1535 lbl_associateSeq.setVisible(true);
1536 cmb_assSeq.setVisible(false);
1540 protected boolean isStructuresDiscovered()
1542 return discoveredStructuresSet != null
1543 && !discoveredStructuresSet.isEmpty();
1546 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1548 // Doing a search for "1" or "1c" is valuable?
1549 // Those work but are enormously slow.
1552 protected void txt_search_ActionPerformed()
1554 String text = txt_search.getText().trim();
1555 if (text.length() >= PDB_ID_MIN)
1562 errorWarning.setLength(0);
1563 isValidPBDEntry = false;
1564 if (text.length() > 0)
1566 // TODO move this pdb id search into the PDB specific
1568 // for moment, it will work fine as is because it is self-contained
1569 String searchTerm = text.toLowerCase(Locale.ROOT);
1570 searchTerm = searchTerm.split(":")[0];
1571 // jalview.bin.Console.outPrintln(">>>>> search term : " +
1573 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1574 FTSRestRequest pdbRequest = new FTSRestRequest();
1575 pdbRequest.setAllowEmptySeq(false);
1576 pdbRequest.setResponseSize(1);
1577 pdbRequest.setFieldToSearchBy("(pdb_id:");
1578 pdbRequest.setWantedFields(wantedFields);
1579 pdbRequest.setSearchTerm(searchTerm + ")");
1580 pdbRequest.setAssociatedSequence(selectedSequence);
1581 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1582 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1583 FTSRestResponse resultList;
1586 resultList = pdbRestClient.executeRequest(pdbRequest);
1587 } catch (Exception e)
1589 errorWarning.append(e.getMessage());
1593 validateSelections();
1595 if (resultList.getSearchSummary() != null
1596 && resultList.getSearchSummary().size() > 0)
1598 isValidPBDEntry = true;
1601 validateSelections();
1607 protected void tabRefresh()
1609 if (selectedSequences != null)
1611 lbl_loading.setVisible(true);
1612 Thread refreshThread = new Thread(new Runnable()
1617 fetchStructuresMetaData();
1618 // populateFilterComboBox(true, cachedPDBExists);
1621 ((FilterOption) cmb_filterOption.getSelectedItem())
1623 lbl_loading.setVisible(false);
1626 refreshThread.start();
1630 public class PDBEntryTableModel extends AbstractTableModel
1632 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1635 private List<CachedPDB> pdbEntries;
1637 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1639 this.pdbEntries = new ArrayList<>(pdbEntries);
1643 public String getColumnName(int columnIndex)
1645 return columns[columnIndex];
1649 public int getRowCount()
1651 return pdbEntries.size();
1655 public int getColumnCount()
1657 return columns.length;
1661 public boolean isCellEditable(int row, int column)
1667 public Object getValueAt(int rowIndex, int columnIndex)
1669 Object value = "??";
1670 CachedPDB entry = pdbEntries.get(rowIndex);
1671 switch (columnIndex)
1674 value = entry.getSequence();
1677 value = entry.getQualifiedId();
1680 value = entry.getPdbEntry().getChainCode() == null ? "_"
1681 : entry.getPdbEntry().getChainCode();
1684 value = entry.getPdbEntry().getType();
1687 value = entry.getPdbEntry().getFile();
1694 public Class<?> getColumnClass(int columnIndex)
1696 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1699 public CachedPDB getPDBEntryAt(int row)
1701 return pdbEntries.get(row);
1706 private class CachedPDB
1708 private SequenceI sequence;
1710 private PDBEntry pdbEntry;
1712 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1714 this.sequence = sequence;
1715 this.pdbEntry = pdbEntry;
1718 public String getQualifiedId()
1720 if (pdbEntry.hasProvider())
1722 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1724 return pdbEntry.toString();
1727 public SequenceI getSequence()
1732 public PDBEntry getPdbEntry()
1739 private IProgressIndicator progressBar;
1742 public void setProgressBar(String message, long id)
1744 if (!Platform.isHeadless() && progressBar != null)
1745 progressBar.setProgressBar(message, id);
1749 public void registerHandler(long id, IProgressIndicatorHandler handler)
1751 if (progressBar != null)
1752 progressBar.registerHandler(id, handler);
1756 public boolean operationInProgress()
1758 return progressBar == null ? false : progressBar.operationInProgress();
1761 public JalviewStructureDisplayI getOpenedStructureViewer()
1763 return sViewer == null ? null : sViewer.sview;
1767 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1769 data.setDocFieldPrefs(newPrefs);
1775 * @return true when all initialisation threads have finished and dialog is
1778 public boolean isDialogVisible()
1780 return mainFrame != null && data != null && cmb_filterOption != null
1781 && mainFrame.isVisible()
1782 && cmb_filterOption.getSelectedItem() != null;
1787 * @return true if the 3D-Beacons query button will/has been displayed
1789 public boolean isCanQueryTDB()
1794 public boolean isNotQueriedTDBYet()
1796 return notQueriedTDBYet;
1800 * Open a single structure file for a given sequence
1802 public static void openStructureFileForSequence(
1803 StructureSelectionManager ssm, StructureChooser sc,
1804 AlignmentPanel ap, SequenceI seq, boolean prompt,
1805 String sFilename, TFType tft, String paeFilename,
1806 boolean doXferSettings)
1808 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1809 paeFilename, false, true, doXferSettings, null);
1812 public static StructureViewer openStructureFileForSequence(
1813 StructureSelectionManager ssm, StructureChooser sc,
1814 AlignmentPanel ap, SequenceI seq, boolean prompt,
1815 String sFilename, TFType tft, String paeFilename,
1816 boolean forceHeadless, boolean showRefAnnotations,
1817 boolean doXferSettings, ViewerType viewerType)
1819 StructureViewer sv = null;
1820 boolean headless = forceHeadless;
1825 // suppress structure viewer's external service queries
1826 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false,
1831 ssm = ap.getStructureSelectionManager();
1834 PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1835 sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
1836 tft, paeFilename, doXferSettings);
1838 // if headless, "false" in the sc constructor above will avoid GUI behaviour
1839 // in sc.launchStructureViewer()
1840 if (!headless && !(viewerType == null))
1842 sv = sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1844 { seq }, viewerType);
1847 sc.mainFrame.dispose();
1849 if (showRefAnnotations)
1851 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1857 public static void showReferenceAnnotationsForSequence(AlignFrame af,
1860 AlignViewport av = af.getCurrentView();
1861 AlignmentI al = av.getAlignment();
1863 List<SequenceI> forSequences = new ArrayList<>();
1864 forSequences.add(sequence);
1865 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1866 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1868 final SequenceGroup selectionGroup = av.getSelectionGroup();
1869 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1870 for (AlignmentViewPanel ap : af.getAlignPanels())
1872 // required to readjust the height and position of the PAE
1874 ap.adjustAnnotationHeight();