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.MessageManager;
82 import jalview.util.Platform;
83 import jalview.util.StringUtils;
84 import jalview.ws.DBRefFetcher;
85 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
86 import jalview.ws.datamodel.alphafold.PAEContactMatrix;
87 import jalview.ws.seqfetcher.DbSourceProxy;
88 import jalview.ws.sifts.SiftsSettings;
91 * Provides the behaviors for the Structure chooser Panel
96 @SuppressWarnings("serial")
97 public class StructureChooser extends GStructureChooser
98 implements IProgressIndicator
100 private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
103 * warn user if need to fetch more than this many uniprot records at once
105 private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
107 private SequenceI selectedSequence;
109 private SequenceI[] selectedSequences;
111 private IProgressIndicator progressIndicator;
113 private Collection<FTSData> discoveredStructuresSet;
115 private StructureChooserQuerySource data;
118 protected FTSDataColumnPreferences getFTSDocFieldPrefs()
120 return data.getDocFieldPrefs();
123 private String selectedPdbFileName;
125 private TFType localPdbTempfacType;
127 private String localPdbPaeMatrixFileName;
129 private boolean isValidPBDEntry;
131 private boolean cachedPDBExists;
133 private Collection<FTSData> lastDiscoveredStructuresSet;
135 private boolean canQueryTDB = false;
137 private boolean notQueriedTDBYet = true;
139 List<SequenceI> seqsWithoutSourceDBRef = null;
141 private boolean showChooserGUI = true;
143 private static StructureViewer lastTargetedView = null;
145 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
148 this(selectedSeqs, selectedSeq, ap, true);
151 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
152 AlignmentPanel ap, boolean showGUI)
154 // which FTS engine to use
155 data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
159 this.selectedSequence = selectedSeq;
160 this.selectedSequences = selectedSeqs;
161 this.progressIndicator = (ap == null) ? null : ap.alignFrame;
162 this.showChooserGUI = showGUI;
168 * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
169 * least one structure are discovered.
171 private void populateSeqsWithoutSourceDBRef()
173 seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
174 boolean needCanonical = false;
175 for (SequenceI seq : selectedSequences)
179 int dbRef = ThreeDBStructureChooserQuerySource
180 .checkUniprotRefs(seq.getDBRefs());
185 // need to retrieve canonicals
186 needCanonical = true;
187 seqsWithoutSourceDBRef.add(seq);
191 // could be a sequence with pdb ref
192 if (seq.getAllPDBEntries() == null
193 || seq.getAllPDBEntries().size() == 0)
195 seqsWithoutSourceDBRef.add(seq);
201 // retrieve database refs for protein sequences
202 if (!seqsWithoutSourceDBRef.isEmpty())
207 // triggers display of the 'Query TDB' button
208 notQueriedTDBYet = true;
214 * Initializes parameters used by the Structure Chooser Panel
216 protected void init()
218 if (!Jalview.isHeadlessMode())
220 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
223 chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
224 btn_queryTDB.addActionListener(new ActionListener()
228 public void actionPerformed(ActionEvent e)
230 promptForTDBFetch(false);
234 Executors.defaultThreadFactory().newThread(new Runnable()
239 populateSeqsWithoutSourceDBRef();
240 initialStructureDiscovery();
248 private void initialStructureDiscovery()
250 // check which FTS engine to use
251 data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
253 // ensure a filter option is in force for search
254 populateFilterComboBox(true, cachedPDBExists);
256 // looks for any existing structures already loaded
257 // for the sequences (the cached ones)
258 // then queries the StructureChooserQuerySource to
259 // discover more structures.
261 // Possible optimisation is to only begin querying
262 // the structure chooser if there are no cached structures.
264 long startTime = System.currentTimeMillis();
265 updateProgressIndicator(
266 MessageManager.getString("status.loading_cached_pdb_entries"),
268 loadLocalCachedPDBEntries();
269 updateProgressIndicator(null, startTime);
270 updateProgressIndicator(
271 MessageManager.getString("status.searching_for_pdb_structures"),
273 fetchStructuresMetaData();
274 // revise filter options if no results were found
275 populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
276 discoverStructureViews();
277 updateProgressIndicator(null, startTime);
278 mainFrame.setVisible(showChooserGUI);
283 * raises dialog for Uniprot fetch followed by 3D beacons search
286 * - when true, don't ask, just fetch
288 public void promptForTDBFetch(boolean ignoreGui)
290 final long progressId = System.currentTimeMillis();
292 // final action after prompting and discovering db refs
293 final Runnable strucDiscovery = new Runnable()
298 mainFrame.setEnabled(false);
299 cmb_filterOption.setEnabled(false);
300 progressBar.setProgressBar(
301 MessageManager.getString("status.searching_3d_beacons"),
303 btn_queryTDB.setEnabled(false);
304 // TODO: warn if no accessions discovered
305 populateSeqsWithoutSourceDBRef();
306 // redo initial discovery - this time with 3d beacons
308 previousWantedFields = null;
309 lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
310 cmb_filterOption.setSelectedItem(null);
311 cachedPDBExists = false; // reset to initial
312 initialStructureDiscovery();
313 if (!isStructuresDiscovered())
315 progressBar.setProgressBar(MessageManager.getString(
316 "status.no_structures_discovered_from_3d_beacons"),
318 btn_queryTDB.setToolTipText(MessageManager.getString(
319 "status.no_structures_discovered_from_3d_beacons"));
320 btn_queryTDB.setEnabled(false);
321 pnl_queryTDB.setVisible(false);
325 cmb_filterOption.setSelectedIndex(0); // select 'best'
326 btn_queryTDB.setVisible(false);
327 pnl_queryTDB.setVisible(false);
328 progressBar.setProgressBar(null, progressId);
330 mainFrame.setEnabled(true);
331 cmb_filterOption.setEnabled(true);
335 final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
339 public void finished()
341 // filter has been selected, so we set flag to remove ourselves
342 notQueriedTDBYet = false;
343 // new thread to discover structures - via 3d beacons
344 Executors.defaultThreadFactory().newThread(strucDiscovery).start();
349 // fetch db refs if OK pressed
350 final Runnable discoverCanonicalDBrefs = () -> {
351 btn_queryTDB.setEnabled(false);
352 populateSeqsWithoutSourceDBRef();
354 final int y = seqsWithoutSourceDBRef.size();
357 final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
358 .toArray(new SequenceI[y]);
359 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
360 progressBar, new DbSourceProxy[]
361 { new jalview.ws.dbsources.Uniprot() }, null, false);
362 dbRefFetcher.addListener(afterDbRefFetch);
363 // ideally this would also gracefully run with callbacks
365 dbRefFetcher.fetchDBRefs(true);
369 // call finished action directly
370 afterDbRefFetch.finished();
373 final Runnable revertview = () -> {
374 if (lastSelected != null)
376 cmb_filterOption.setSelectedItem(lastSelected);
379 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
380 THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
381 Console.debug("Using Uniprot fetch threshold of " + threshold);
382 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
384 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
387 // need cancel and no to result in the discoverPDB action - mocked is
388 // 'cancel' TODO: mock should be OK
390 StructureChooser thisSC = this;
391 JvOptionPane.newOptionDialog(thisSC.getFrame())
392 .setResponseHandler(JvOptionPane.OK_OPTION,
393 discoverCanonicalDBrefs)
394 .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
395 .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
397 MessageManager.formatMessage(
398 "label.fetch_references_for_3dbeacons",
399 seqsWithoutSourceDBRef.size()),
400 MessageManager.getString("label.3dbeacons"),
401 JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
403 { MessageManager.getString("action.ok"),
404 MessageManager.getString("action.cancel") },
405 MessageManager.getString("action.ok"), false);
409 * Builds a drop-down choice list of existing structure viewers to which new
410 * structures may be added. If this list is empty then it, and the 'Add'
411 * button, are hidden.
413 private void discoverStructureViews()
415 if (Desktop.instance != null)
417 targetView.removeAllItems();
418 if (lastTargetedView != null && !lastTargetedView.isVisible())
420 lastTargetedView = null;
422 int linkedViewsAt = 0;
423 for (StructureViewerBase view : Desktop.instance
424 .getStructureViewers(null, null))
426 StructureViewer viewHandler = (lastTargetedView != null
427 && lastTargetedView.sview == view) ? lastTargetedView
428 : StructureViewer.reconfigure(view);
430 if (view.isLinkedWith(ap))
432 targetView.insertItemAt(viewHandler, linkedViewsAt++);
436 targetView.addItem(viewHandler);
441 * show option to Add to viewer if at least 1 viewer found
443 targetView.setVisible(false);
444 if (targetView.getItemCount() > 0)
446 targetView.setVisible(true);
447 if (lastTargetedView != null)
449 targetView.setSelectedItem(lastTargetedView);
453 targetView.setSelectedIndex(0);
456 btn_add.setVisible(targetView.isVisible());
461 * Updates the progress indicator with the specified message
464 * displayed message for the operation
466 * unique handle for this indicator
468 protected void updateProgressIndicator(String message, long id)
470 if (progressIndicator != null)
472 progressIndicator.setProgressBar(message, id);
477 * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
480 void fetchStructuresMetaData()
482 long startTime = System.currentTimeMillis();
483 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
484 .getStructureSummaryFields();
486 discoveredStructuresSet = new LinkedHashSet<>();
487 HashSet<String> errors = new HashSet<>();
489 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
492 for (SequenceI seq : selectedSequences)
495 FTSRestResponse resultList;
498 resultList = data.fetchStructuresMetaData(seq, wantedFields,
499 selectedFilterOpt, !chk_invertFilter.isSelected());
500 // null response means the FTSengine didn't yield a query for this
501 // consider designing a special exception if we really wanted to be
503 if (resultList == null)
507 } catch (Exception e)
509 Console.debugPrintStackTrace(e);
510 errors.add(e.getMessage());
513 if (resultList.getSearchSummary() != null
514 && !resultList.getSearchSummary().isEmpty())
516 discoveredStructuresSet.addAll(resultList.getSearchSummary());
520 int noOfStructuresFound = 0;
521 String totalTime = (System.currentTimeMillis() - startTime)
523 if (discoveredStructuresSet != null
524 && !discoveredStructuresSet.isEmpty())
527 .setModel(data.getTableModel(discoveredStructuresSet));
529 noOfStructuresFound = discoveredStructuresSet.size();
530 lastDiscoveredStructuresSet = discoveredStructuresSet;
531 mainFrame.setTitle(MessageManager.formatMessage(
532 "label.structure_chooser_no_of_structures",
533 noOfStructuresFound, totalTime));
537 mainFrame.setTitle(MessageManager
538 .getString("label.structure_chooser_manual_association"));
539 if (errors.size() > 0)
541 StringBuilder errorMsg = new StringBuilder();
542 for (String error : errors)
544 errorMsg.append(error).append("\n");
546 if (!Jalview.isHeadlessMode())
548 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
549 MessageManager.getString("label.pdb_web-service_error"),
550 JvOptionPane.ERROR_MESSAGE);
555 MessageManager.getString("label.pdb_web-service_error"));
556 Console.debug(errorMsg.toString());
562 protected void loadLocalCachedPDBEntries()
564 ArrayList<CachedPDB> entries = new ArrayList<>();
565 for (SequenceI seq : selectedSequences)
567 if (seq.getDatasetSequence() != null
568 && seq.getDatasetSequence().getAllPDBEntries() != null)
570 for (PDBEntry pdbEntry : seq.getDatasetSequence()
573 if (pdbEntry.getFile() != null)
575 entries.add(new CachedPDB(seq, pdbEntry));
580 cachedPDBExists = !entries.isEmpty();
581 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
582 tbl_local_pdb.setModel(tableModelx);
586 * Filters a given list of discovered structures based on supplied argument
588 * @param fieldToFilterBy
589 * the field to filter by
591 void filterResultSet(final String fieldToFilterBy)
593 Thread filterThread = new Thread(new Runnable()
599 long startTime = System.currentTimeMillis();
600 lbl_loading.setVisible(true);
601 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
602 .getStructureSummaryFields();
603 Collection<FTSData> filteredResponse = new HashSet<>();
604 HashSet<String> errors = new HashSet<>();
606 for (SequenceI seq : selectedSequences)
609 FTSRestResponse resultList;
612 resultList = data.selectFirstRankedQuery(seq,
613 discoveredStructuresSet, wantedFields, fieldToFilterBy,
614 !chk_invertFilter.isSelected());
616 } catch (Exception e)
618 Console.debugPrintStackTrace(e);
619 errors.add(e.getMessage());
622 if (resultList.getSearchSummary() != null
623 && !resultList.getSearchSummary().isEmpty())
625 filteredResponse.addAll(resultList.getSearchSummary());
629 String totalTime = (System.currentTimeMillis() - startTime)
631 if (!filteredResponse.isEmpty())
633 final int filterResponseCount = filteredResponse.size();
634 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
635 reorderedStructuresSet.addAll(filteredResponse);
636 reorderedStructuresSet.addAll(discoveredStructuresSet);
638 .setModel(data.getTableModel(reorderedStructuresSet));
640 FTSRestResponse.configureTableColumn(getResultTable(),
641 wantedFields, tempUserPrefs);
642 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
643 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
644 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
645 // Update table selection model here
646 getResultTable().addRowSelectionInterval(0,
647 filterResponseCount - 1);
648 mainFrame.setTitle(MessageManager.formatMessage(
649 "label.structure_chooser_filter_time", totalTime));
653 mainFrame.setTitle(MessageManager.formatMessage(
654 "label.structure_chooser_filter_time", totalTime));
655 if (errors.size() > 0)
657 StringBuilder errorMsg = new StringBuilder();
658 for (String error : errors)
660 errorMsg.append(error).append("\n");
662 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
663 MessageManager.getString("label.pdb_web-service_error"),
664 JvOptionPane.ERROR_MESSAGE);
668 lbl_loading.setVisible(false);
670 validateSelections();
673 filterThread.start();
677 * Handles action event for btn_pdbFromFile
680 protected void pdbFromFile_actionPerformed()
682 // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
685 JalviewFileChooser chooser = new JalviewFileChooser(
686 Cache.getProperty("LAST_DIRECTORY"));
687 chooser.setFileView(new JalviewFileView());
688 chooser.setDialogTitle(
689 MessageManager.formatMessage("label.select_pdb_file_for",
690 selectedSequence.getDisplayId(false)));
691 chooser.setToolTipText(MessageManager.formatMessage(
692 "label.load_pdb_file_associate_with_sequence",
693 selectedSequence.getDisplayId(false)));
695 int value = chooser.showOpenDialog(null);
696 if (value == JalviewFileChooser.APPROVE_OPTION)
698 selectedPdbFileName = chooser.getSelectedFile().getPath();
699 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
700 boolean guessTFType = localPdbPaeMatrixFileName == null;
701 localPdbPaeMatrixFileName = guessPAEFilename();
702 guessTFType |= localPdbPaeMatrixFileName != null;
703 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
705 && alphaFold.search(new File(selectedPdbFileName).getName())
706 && !tempFacAsChanged)
708 // localPdbPaeMatrixFileName was null and now isn't and filename could
709 // well be AlphaFold and user hasn't adjusted the tempFacType
710 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
712 validateSelections();
717 * Handles action event for btn_paeMatrixFile
720 protected void paeMatrixFile_actionPerformed()
722 File pdbFile = new File(selectedPdbFileName);
723 String setFile = Cache.getProperty("LAST_DIRECTORY");
724 if (localPdbPaeMatrixFileName != null)
726 File paeFile = new File(localPdbPaeMatrixFileName);
727 if (paeFile.exists())
728 setFile = paeFile.getAbsolutePath();
729 else if (paeFile.getParentFile().exists())
730 setFile = paeFile.getParentFile().getAbsolutePath();
734 String guess = guessPAEFilename();
738 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
739 chooser.setFileView(new JalviewFileView());
740 chooser.setDialogTitle(MessageManager.formatMessage(
741 "label.select_pae_matrix_file_for", pdbFile.getName()));
742 chooser.setToolTipText(MessageManager.formatMessage(
743 "label.load_pae_matrix_file_associate_with_structure",
746 // TODO convert to Callable/Promise
747 int value = chooser.showOpenDialog(null);
748 if (value == JalviewFileChooser.APPROVE_OPTION)
750 String fileName = chooser.getSelectedFile().getPath();
753 PAEContactMatrix.validateContactMatrixFile(fileName);
754 } catch (Exception thr)
756 JvOptionPane.showInternalMessageDialog(this, MessageManager
757 .formatMessage("label.couldnt_load_file", new Object[]
758 { fileName }) + "<br>" + thr.getLocalizedMessage(),
759 MessageManager.getString("label.error_loading_file"),
760 JvOptionPane.WARNING_MESSAGE);
761 Console.error("Couldn't import " + fileName + " as a PAE matrix",
765 localPdbPaeMatrixFileName = fileName;
766 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
768 validateAssociationFromFile();
771 private String guessPAEFilename()
773 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
774 || selectedPdbFileName.toLowerCase(Locale.ROOT)
777 String jsonExt = selectedPdbFileName.substring(0,
778 selectedPdbFileName.length() - 4) + ".json";
779 // AlphaFold naming scheme
780 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
781 "predicted_aligned_error");
782 // nf-core mode naming scheme
783 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
785 if (new File(guessFile1).exists())
789 else if (new File(jsonExt).exists())
793 else if (new File(guessFile2).exists())
802 * Populates the filter combo-box options dynamically depending on discovered
805 protected void populateFilterComboBox(boolean haveData,
806 boolean cachedPDBExist)
808 populateFilterComboBox(haveData, cachedPDBExist, null);
812 * Populates the filter combo-box options dynamically depending on discovered
815 protected void populateFilterComboBox(boolean haveData,
816 boolean cachedPDBExist, FilterOption lastSel)
820 * temporarily suspend the change listener behaviour
822 cmb_filterOption.removeItemListener(this);
824 cmb_filterOption.removeAllItems();
827 List<FilterOption> filters = data
828 .getAvailableFilterOptions(VIEWS_FILTER);
829 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
830 lastDiscoveredStructuresSet);
832 for (FilterOption filter : filters)
834 if (lastSel != null && filter.equals(lastSel))
839 cmb_filterOption.addItem(filter);
843 cmb_filterOption.addItem(
844 new FilterOption(MessageManager.getString("label.enter_pdb_id"),
845 "-", VIEWS_ENTER_ID, false, null));
846 cmb_filterOption.addItem(
847 new FilterOption(MessageManager.getString("label.from_file"),
848 "-", VIEWS_FROM_FILE, false, null));
849 if (canQueryTDB && notQueriedTDBYet)
851 btn_queryTDB.setVisible(true);
852 pnl_queryTDB.setVisible(true);
857 FilterOption cachedOption = new FilterOption(
858 MessageManager.getString("label.cached_structures"), "-",
859 VIEWS_LOCAL_PDB, false, null);
860 cmb_filterOption.addItem(cachedOption);
863 cmb_filterOption.setSelectedItem(cachedOption);
868 cmb_filterOption.setSelectedIndex(selSet);
870 cmb_filterOption.addItemListener(this);
874 * Updates the displayed view based on the selected filter option
876 protected void updateCurrentView()
878 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
881 if (lastSelected == selectedFilterOpt)
883 // don't need to do anything, probably
886 // otherwise, record selection
887 // and update the layout and dialog accordingly
888 lastSelected = selectedFilterOpt;
890 layout_switchableViews.show(pnl_switchableViews,
891 selectedFilterOpt.getView());
892 String filterTitle = mainFrame.getTitle();
893 mainFrame.setTitle(frameTitle);
894 chk_invertFilter.setVisible(false);
896 if (selectedFilterOpt.getView() == VIEWS_FILTER)
898 mainFrame.setTitle(filterTitle);
899 // TDB Query has no invert as yet
900 chk_invertFilter.setVisible(selectedFilterOpt
901 .getQuerySource() instanceof PDBStructureChooserQuerySource);
903 if (data != selectedFilterOpt.getQuerySource()
904 || data.needsRefetch(selectedFilterOpt))
906 data = selectedFilterOpt.getQuerySource();
907 // rebuild the views completely, since prefs will also change
913 filterResultSet(selectedFilterOpt.getValue());
916 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
917 || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
919 mainFrame.setTitle(MessageManager
920 .getString("label.structure_chooser_manual_association"));
921 idInputAssSeqPanel.loadCmbAssSeq();
922 fileChooserAssSeqPanel.loadCmbAssSeq();
924 validateSelections();
928 * Validates user selection and enables the 'Add' and 'New View' buttons if
929 * all parameters are correct (the Add button will only be visible if there is
930 * at least one existing structure viewer open). This basically means at least
931 * one structure selected and no error messages.
933 * The 'Superpose Structures' option is enabled if either more than one
934 * structure is selected, or the 'Add' to existing view option is enabled, and
935 * disabled if the only option is to open a new view of a single structure.
938 protected void validateSelections()
940 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
942 btn_add.setEnabled(false);
943 String currentView = selectedFilterOpt.getView();
944 int selectedCount = 0;
945 if (currentView == VIEWS_FILTER)
947 selectedCount = getResultTable().getSelectedRows().length;
948 if (selectedCount > 0)
950 btn_add.setEnabled(true);
953 else if (currentView == VIEWS_LOCAL_PDB)
955 selectedCount = tbl_local_pdb.getSelectedRows().length;
956 if (selectedCount > 0)
958 btn_add.setEnabled(true);
961 else if (currentView == VIEWS_ENTER_ID)
963 validateAssociationEnterPdb();
965 else if (currentView == VIEWS_FROM_FILE)
967 validateAssociationFromFile();
970 btn_newView.setEnabled(btn_add.isEnabled());
973 * enable 'Superpose' option if more than one structure is selected,
974 * or there are view(s) available to add structure(s) to
977 .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
981 protected boolean showPopupFor(int selectedRow, int x, int y)
983 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
985 String currentView = selectedFilterOpt.getView();
987 if (currentView == VIEWS_FILTER
988 && data instanceof ThreeDBStructureChooserQuerySource)
991 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
992 .getFTSDataFor(getResultTable(), selectedRow,
993 discoveredStructuresSet);
994 String pageUrl = row.getModelViewUrl();
995 JPopupMenu popup = new JPopupMenu("3D Beacons");
996 JMenuItem viewUrl = new JMenuItem("View model web page");
997 viewUrl.addActionListener(new ActionListener()
1000 public void actionPerformed(ActionEvent e)
1002 Desktop.showUrl(pageUrl);
1006 SwingUtilities.invokeLater(new Runnable()
1011 popup.show(getResultTable(), x, y);
1016 // event not handled by us
1021 * Validates inputs from the Manual PDB entry panel
1023 protected void validateAssociationEnterPdb()
1025 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
1026 .getCmb_assSeq().getSelectedItem();
1027 lbl_pdbManualFetchStatus.setIcon(errorImage);
1028 lbl_pdbManualFetchStatus.setToolTipText("");
1029 if (txt_search.getText().length() > 0)
1031 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1032 MessageManager.formatMessage("info.no_pdb_entry_found_for",
1033 txt_search.getText())));
1036 if (errorWarning.length() > 0)
1038 lbl_pdbManualFetchStatus.setIcon(warningImage);
1039 lbl_pdbManualFetchStatus.setToolTipText(
1040 JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1043 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1044 .equalsIgnoreCase("-Select Associated Seq-"))
1046 txt_search.setEnabled(true);
1047 if (isValidPBDEntry)
1049 btn_add.setEnabled(true);
1050 lbl_pdbManualFetchStatus.setToolTipText("");
1051 lbl_pdbManualFetchStatus.setIcon(goodImage);
1056 txt_search.setEnabled(false);
1057 lbl_pdbManualFetchStatus.setIcon(errorImage);
1062 * Validates inputs for the manual PDB file selection options
1064 protected void validateAssociationFromFile()
1066 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1067 .getCmb_assSeq().getSelectedItem();
1068 // lbl_fromFileStatus.setIcon(errorImage);
1069 String pdbFileString = "";
1070 String pdbFileTooltip = "";
1071 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1072 .getName().equalsIgnoreCase("-Select Associated Seq-")))
1074 btn_pdbFromFile.setEnabled(true);
1075 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1077 btn_add.setEnabled(true);
1078 // lbl_fromFileStatus.setIcon(goodImage);
1079 pdbFileString = new File(selectedPdbFileName).getName();
1080 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1081 setPdbOptionsEnabled(true);
1085 pdbFileString = MessageManager.getString("label.none");
1086 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1087 setPdbOptionsEnabled(false);
1092 btn_pdbFromFile.setEnabled(false);
1093 setPdbOptionsEnabled(false);
1094 // lbl_fromFileStatus.setIcon(errorImage);
1095 pdbFileString = MessageManager.getString("label.none");
1096 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1098 lbl_pdbFile.setText(pdbFileString);
1099 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1102 String paeFileString = "";
1103 String paeFileTooltip = "";
1104 if (localPdbPaeMatrixFileName != null
1105 && localPdbPaeMatrixFileName.length() > 0)
1107 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1108 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1113 paeFileString = MessageManager.getString("label.none");
1114 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1116 lbl_paeFile.setText(paeFileString);
1117 lbl_paeFile.setToolTipText(paeFileTooltip);
1121 protected void cmbAssSeqStateChanged()
1123 validateSelections();
1126 private FilterOption lastSelected = null;
1129 * Handles the state change event for the 'filter' combo-box and 'invert'
1133 protected void stateChanged(ItemEvent e)
1135 if (e.getSource() instanceof JCheckBox)
1137 updateCurrentView();
1141 if (e.getStateChange() == ItemEvent.SELECTED)
1143 updateCurrentView();
1150 * select structures for viewing by their PDB IDs
1153 * @return true if structures were found and marked as selected
1155 public boolean selectStructure(String... pdbids)
1157 boolean found = false;
1159 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1160 .getSelectedItem());
1161 String currentView = selectedFilterOpt.getView();
1162 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1163 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1165 if (restable == null)
1167 // can't select (enter PDB ID, or load file - need to also select which
1168 // sequence to associate with)
1172 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1173 for (int r = 0; r < restable.getRowCount(); r++)
1175 for (int p = 0; p < pdbids.length; p++)
1177 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1178 .equalsIgnoreCase(pdbids[p]))
1180 restable.setRowSelectionInterval(r, r);
1189 * Handles the 'New View' action
1192 protected void newView_ActionPerformed()
1194 targetView.setSelectedItem(null);
1195 showStructures(false);
1199 * Handles the 'Add to existing viewer' action
1202 protected void add_ActionPerformed()
1204 showStructures(false);
1208 * structure viewer opened by this dialog, or null
1210 private StructureViewer sViewer = null;
1212 public void showStructures(boolean waitUntilFinished)
1215 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1217 final int preferredHeight = pnl_filter.getHeight();
1218 btn_add.setEnabled(false);
1219 btn_newView.setEnabled(false);
1220 btn_cancel.setEnabled(false);
1221 actionsPanel.setEnabled(false);
1223 final String progress = MessageManager
1224 .getString("label.working_ellipsis");
1225 setProgressBar(progress, progress.hashCode());
1226 Runnable viewStruc = new Runnable()
1231 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1232 .getSelectedItem());
1233 String currentView = selectedFilterOpt.getView();
1234 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1237 if (currentView == VIEWS_FILTER)
1239 int[] selectedRows = restable.getSelectedRows();
1240 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1241 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1242 pdbEntriesToView = data.collectSelectedRows(restable,
1243 selectedRows, selectedSeqsToView);
1245 SequenceI[] selectedSeqs = selectedSeqsToView
1246 .toArray(new SequenceI[selectedSeqsToView.size()]);
1247 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1250 else if (currentView == VIEWS_LOCAL_PDB)
1252 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1253 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1255 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1257 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1259 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1260 for (int row : selectedRows)
1262 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1263 .getModel()).getPDBEntryAt(row).getPdbEntry();
1265 pdbEntriesToView[count++] = pdbEntry;
1266 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1267 .getValueAt(row, refSeqColIndex);
1268 selectedSeqsToView.add(selectedSeq);
1270 SequenceI[] selectedSeqs = selectedSeqsToView
1271 .toArray(new SequenceI[selectedSeqsToView.size()]);
1272 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1275 else if (currentView == VIEWS_ENTER_ID)
1277 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1278 .getCmb_assSeq().getSelectedItem()).getSequence();
1279 if (userSelectedSeq != null)
1281 selectedSequence = userSelectedSeq;
1283 String pdbIdStr = txt_search.getText();
1284 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1285 if (pdbEntry == null)
1287 pdbEntry = new PDBEntry();
1288 if (pdbIdStr.split(":").length > 1)
1290 pdbEntry.setId(pdbIdStr.split(":")[0]);
1291 pdbEntry.setChainCode(
1292 pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1296 pdbEntry.setId(pdbIdStr);
1298 pdbEntry.setType(PDBEntry.Type.PDB);
1299 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1302 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1303 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1305 { selectedSequence });
1307 else if (currentView == VIEWS_FROM_FILE)
1309 StructureChooser sc = StructureChooser.this;
1310 TFType tft = (TFType) sc.combo_tempFacAs.getSelectedItem();
1311 String paeFilename = sc.localPdbPaeMatrixFileName;
1312 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1313 .getCmb_assSeq().getSelectedItem();
1314 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1315 if (userSelectedSeq != null)
1317 selectedSequence = userSelectedSeq;
1319 String pdbFilename = selectedPdbFileName;
1321 StructureChooser.openStructureFileForSequence(ssm, sc, ap,
1322 selectedSequence, true, pdbFilename, tft, paeFilename,
1325 SwingUtilities.invokeLater(new Runnable()
1330 setProgressBar("Complete.", progress.hashCode());
1331 closeAction(preferredHeight);
1332 mainFrame.dispose();
1337 Thread runner = new Thread(viewStruc);
1339 if (waitUntilFinished)
1341 while (sViewer == null ? runner.isAlive()
1342 : (sViewer.sview == null ? true
1343 : !sViewer.sview.hasMapping()))
1348 } catch (InterruptedException ie)
1357 * Answers a structure viewer (new or existing) configured to superimpose
1358 * added structures or not according to the user's choice
1363 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1365 Object sv = targetView.getSelectedItem();
1367 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1371 * Adds PDB structures to a new or existing structure viewer
1374 * @param pdbEntriesToView
1379 private StructureViewer launchStructureViewer(
1380 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1381 final AlignmentPanel alignPanel, SequenceI[] sequences)
1383 return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
1387 private StructureViewer launchStructureViewer(
1388 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1389 final AlignmentPanel alignPanel, SequenceI[] sequences,
1390 ViewerType viewerType)
1392 long progressId = sequences.hashCode();
1393 setProgressBar(MessageManager
1394 .getString("status.launching_3d_structure_viewer"), progressId);
1395 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1396 boolean superimpose = chk_superpose.isSelected();
1397 theViewer.setSuperpose(superimpose);
1399 // if we're running in --headless mode make this viewer synchronous
1400 if (Jalview.isHeadlessMode())
1402 theViewer.setAsync(false);
1406 * remember user's choice of superimpose or not
1408 Cache.setProperty(AUTOSUPERIMPOSE,
1409 Boolean.valueOf(superimpose).toString());
1411 setProgressBar(null, progressId);
1412 if (SiftsSettings.isMapWithSifts())
1414 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1416 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1417 // real PDB ID. For moment, we can also safely do this if there is already
1418 // a known mapping between the PDBEntry and the sequence.
1419 for (SequenceI seq : sequences)
1421 PDBEntry pdbe = pdbEntriesToView[p++];
1422 if (pdbe != null && pdbe.getFile() != null)
1424 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1425 if (smm != null && smm.length > 0)
1427 for (StructureMapping sm : smm)
1429 if (sm.getSequence() == seq)
1436 if (seq.getPrimaryDBRefs().isEmpty())
1438 seqsWithoutSourceDBRef.add(seq);
1442 if (!seqsWithoutSourceDBRef.isEmpty())
1444 int y = seqsWithoutSourceDBRef.size();
1445 setProgressBar(MessageManager.formatMessage(
1446 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1448 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1449 .toArray(new SequenceI[y]);
1450 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1451 dbRefFetcher.fetchDBRefs(true);
1453 setProgressBar("Fetch complete.", progressId); // todo i18n
1456 if (pdbEntriesToView.length > 1)
1459 MessageManager.getString(
1460 "status.fetching_3d_structures_for_selected_entries"),
1462 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
1467 setProgressBar(MessageManager.formatMessage(
1468 "status.fetching_3d_structures_for",
1469 pdbEntriesToView[0].getId()), progressId);
1470 // Can we pass a pre-computeMappinged pdbFile?
1471 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel,
1474 setProgressBar(null, progressId);
1475 // remember the last viewer we used...
1476 lastTargetedView = theViewer;
1481 * Populates the combo-box used in associating manually fetched structures to
1482 * a unique sequence when more than one sequence selection is made.
1485 protected void populateCmbAssociateSeqOptions(
1486 JComboBox<AssociateSeqOptions> cmb_assSeq,
1487 JLabel lbl_associateSeq)
1489 cmb_assSeq.removeAllItems();
1491 new AssociateSeqOptions("-Select Associated Seq-", null));
1492 lbl_associateSeq.setVisible(false);
1493 if (selectedSequences.length > 1)
1495 for (SequenceI seq : selectedSequences)
1497 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1502 String seqName = selectedSequence.getDisplayId(false);
1503 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1504 lbl_associateSeq.setText(seqName);
1505 lbl_associateSeq.setVisible(true);
1506 cmb_assSeq.setVisible(false);
1510 protected boolean isStructuresDiscovered()
1512 return discoveredStructuresSet != null
1513 && !discoveredStructuresSet.isEmpty();
1516 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1518 // Doing a search for "1" or "1c" is valuable?
1519 // Those work but are enormously slow.
1522 protected void txt_search_ActionPerformed()
1524 String text = txt_search.getText().trim();
1525 if (text.length() >= PDB_ID_MIN)
1532 errorWarning.setLength(0);
1533 isValidPBDEntry = false;
1534 if (text.length() > 0)
1536 // TODO move this pdb id search into the PDB specific
1538 // for moment, it will work fine as is because it is self-contained
1539 String searchTerm = text.toLowerCase(Locale.ROOT);
1540 searchTerm = searchTerm.split(":")[0];
1541 // jalview.bin.Console.outPrintln(">>>>> search term : " +
1543 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1544 FTSRestRequest pdbRequest = new FTSRestRequest();
1545 pdbRequest.setAllowEmptySeq(false);
1546 pdbRequest.setResponseSize(1);
1547 pdbRequest.setFieldToSearchBy("(pdb_id:");
1548 pdbRequest.setWantedFields(wantedFields);
1549 pdbRequest.setSearchTerm(searchTerm + ")");
1550 pdbRequest.setAssociatedSequence(selectedSequence);
1551 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1552 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1553 FTSRestResponse resultList;
1556 resultList = pdbRestClient.executeRequest(pdbRequest);
1557 } catch (Exception e)
1559 errorWarning.append(e.getMessage());
1563 validateSelections();
1565 if (resultList.getSearchSummary() != null
1566 && resultList.getSearchSummary().size() > 0)
1568 isValidPBDEntry = true;
1571 validateSelections();
1577 protected void tabRefresh()
1579 if (selectedSequences != null)
1581 lbl_loading.setVisible(true);
1582 Thread refreshThread = new Thread(new Runnable()
1587 fetchStructuresMetaData();
1588 // populateFilterComboBox(true, cachedPDBExists);
1591 ((FilterOption) cmb_filterOption.getSelectedItem())
1593 lbl_loading.setVisible(false);
1596 refreshThread.start();
1600 public class PDBEntryTableModel extends AbstractTableModel
1602 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1605 private List<CachedPDB> pdbEntries;
1607 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1609 this.pdbEntries = new ArrayList<>(pdbEntries);
1613 public String getColumnName(int columnIndex)
1615 return columns[columnIndex];
1619 public int getRowCount()
1621 return pdbEntries.size();
1625 public int getColumnCount()
1627 return columns.length;
1631 public boolean isCellEditable(int row, int column)
1637 public Object getValueAt(int rowIndex, int columnIndex)
1639 Object value = "??";
1640 CachedPDB entry = pdbEntries.get(rowIndex);
1641 switch (columnIndex)
1644 value = entry.getSequence();
1647 value = entry.getQualifiedId();
1650 value = entry.getPdbEntry().getChainCode() == null ? "_"
1651 : entry.getPdbEntry().getChainCode();
1654 value = entry.getPdbEntry().getType();
1657 value = entry.getPdbEntry().getFile();
1664 public Class<?> getColumnClass(int columnIndex)
1666 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1669 public CachedPDB getPDBEntryAt(int row)
1671 return pdbEntries.get(row);
1676 private class CachedPDB
1678 private SequenceI sequence;
1680 private PDBEntry pdbEntry;
1682 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1684 this.sequence = sequence;
1685 this.pdbEntry = pdbEntry;
1688 public String getQualifiedId()
1690 if (pdbEntry.hasProvider())
1692 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1694 return pdbEntry.toString();
1697 public SequenceI getSequence()
1702 public PDBEntry getPdbEntry()
1709 private IProgressIndicator progressBar;
1712 public void setProgressBar(String message, long id)
1714 if (!Platform.isHeadless() && progressBar != null)
1715 progressBar.setProgressBar(message, id);
1719 public void registerHandler(long id, IProgressIndicatorHandler handler)
1721 if (progressBar != null)
1722 progressBar.registerHandler(id, handler);
1726 public boolean operationInProgress()
1728 return progressBar == null ? false : progressBar.operationInProgress();
1731 public JalviewStructureDisplayI getOpenedStructureViewer()
1733 return sViewer == null ? null : sViewer.sview;
1737 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1739 data.setDocFieldPrefs(newPrefs);
1745 * @return true when all initialisation threads have finished and dialog is
1748 public boolean isDialogVisible()
1750 return mainFrame != null && data != null && cmb_filterOption != null
1751 && mainFrame.isVisible()
1752 && cmb_filterOption.getSelectedItem() != null;
1757 * @return true if the 3D-Beacons query button will/has been displayed
1759 public boolean isCanQueryTDB()
1764 public boolean isNotQueriedTDBYet()
1766 return notQueriedTDBYet;
1770 * Open a single structure file for a given sequence
1772 public static void openStructureFileForSequence(
1773 StructureSelectionManager ssm, StructureChooser sc,
1774 AlignmentPanel ap, SequenceI seq, boolean prompt,
1775 String sFilename, TFType tft, String paeFilename,
1776 boolean doXferSettings)
1778 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1779 paeFilename, false, true, doXferSettings, null);
1782 public static StructureViewer openStructureFileForSequence(
1783 StructureSelectionManager ssm, StructureChooser sc,
1784 AlignmentPanel ap, SequenceI seq, boolean prompt,
1785 String sFilename, TFType tft, String paeFilename,
1786 boolean forceHeadless, boolean showRefAnnotations,
1787 boolean doXferSettings, ViewerType viewerType)
1789 StructureViewer sv = null;
1790 boolean headless = forceHeadless;
1795 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
1799 ssm = ap.getStructureSelectionManager();
1802 PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1803 sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
1804 tft, paeFilename, doXferSettings);
1806 // if headless, "false" in the sc constructor above will avoid GUI behaviour
1807 // in sc.launchStructureViewer()
1808 if (!headless && !(viewerType == null))
1810 sv = sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1812 { seq }, viewerType);
1815 sc.mainFrame.dispose();
1817 if (showRefAnnotations)
1819 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1825 public static void showReferenceAnnotationsForSequence(AlignFrame af,
1828 AlignViewport av = af.getCurrentView();
1829 AlignmentI al = av.getAlignment();
1831 List<SequenceI> forSequences = new ArrayList<>();
1832 forSequences.add(sequence);
1833 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1834 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1836 final SequenceGroup selectionGroup = av.getSelectionGroup();
1837 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1838 for (AlignmentViewPanel ap : af.getAlignPanels())
1840 // required to readjust the height and position of the PAE
1842 ap.adjustAnnotationHeight();