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.Callable;
37 import java.util.concurrent.Executors;
39 import javax.swing.JCheckBox;
40 import javax.swing.JComboBox;
41 import javax.swing.JLabel;
42 import javax.swing.JMenuItem;
43 import javax.swing.JPopupMenu;
44 import javax.swing.JTable;
45 import javax.swing.SwingUtilities;
46 import javax.swing.table.AbstractTableModel;
48 import com.stevesoft.pat.Regex;
50 import jalview.analysis.AlignmentUtils;
51 import jalview.api.AlignmentViewPanel;
52 import jalview.api.structures.JalviewStructureDisplayI;
53 import jalview.bin.Cache;
54 import jalview.bin.Console;
55 import jalview.bin.Jalview;
56 import jalview.datamodel.AlignmentAnnotation;
57 import jalview.datamodel.AlignmentI;
58 import jalview.datamodel.PDBEntry;
59 import jalview.datamodel.SequenceGroup;
60 import jalview.datamodel.SequenceI;
61 import jalview.ext.jmol.JmolParser;
62 import jalview.fts.api.FTSData;
63 import jalview.fts.api.FTSDataColumnI;
64 import jalview.fts.api.FTSRestClientI;
65 import jalview.fts.core.FTSDataColumnPreferences;
66 import jalview.fts.core.FTSRestRequest;
67 import jalview.fts.core.FTSRestResponse;
68 import jalview.fts.service.pdb.PDBFTSRestClient;
69 import jalview.fts.service.threedbeacons.TDB_FTSData;
70 import jalview.gui.StructureViewer.ViewerType;
71 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
72 import jalview.gui.structurechooser.StructureChooserQuerySource;
73 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
74 import jalview.io.DataSourceType;
75 import jalview.io.JalviewFileChooser;
76 import jalview.io.JalviewFileView;
77 import jalview.jbgui.FilterOption;
78 import jalview.jbgui.GStructureChooser;
79 import jalview.structure.StructureImportSettings.TFType;
80 import jalview.structure.StructureMapping;
81 import jalview.structure.StructureSelectionManager;
82 import jalview.util.MessageManager;
83 import jalview.util.Platform;
84 import jalview.util.StringUtils;
85 import jalview.ws.DBRefFetcher;
86 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
87 import jalview.ws.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 Callable 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();
374 final Callable revertview = () -> {
375 if (lastSelected != null)
377 cmb_filterOption.setSelectedItem(lastSelected);
381 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
382 THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
383 Console.debug("Using Uniprot fetch threshold of " + threshold);
384 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
386 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
389 // need cancel and no to result in the discoverPDB action - mocked is
390 // 'cancel' TODO: mock should be OK
392 StructureChooser thisSC = this;
393 JvOptionPane.newOptionDialog(thisSC.getFrame())
394 .setResponseHandler(JvOptionPane.OK_OPTION,
395 discoverCanonicalDBrefs)
396 .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
397 .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
399 MessageManager.formatMessage(
400 "label.fetch_references_for_3dbeacons",
401 seqsWithoutSourceDBRef.size()),
402 MessageManager.getString("label.3dbeacons"),
403 JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
405 { MessageManager.getString("action.ok"),
406 MessageManager.getString("action.cancel") },
407 MessageManager.getString("action.ok"), false);
411 * Builds a drop-down choice list of existing structure viewers to which new
412 * structures may be added. If this list is empty then it, and the 'Add'
413 * button, are hidden.
415 private void discoverStructureViews()
417 if (Desktop.instance != null)
419 targetView.removeAllItems();
420 if (lastTargetedView != null && !lastTargetedView.isVisible())
422 lastTargetedView = null;
424 int linkedViewsAt = 0;
425 for (StructureViewerBase view : Desktop.instance
426 .getStructureViewers(null, null))
428 StructureViewer viewHandler = (lastTargetedView != null
429 && lastTargetedView.sview == view) ? lastTargetedView
430 : StructureViewer.reconfigure(view);
432 if (view.isLinkedWith(ap))
434 targetView.insertItemAt(viewHandler, linkedViewsAt++);
438 targetView.addItem(viewHandler);
443 * show option to Add to viewer if at least 1 viewer found
445 targetView.setVisible(false);
446 if (targetView.getItemCount() > 0)
448 targetView.setVisible(true);
449 if (lastTargetedView != null)
451 targetView.setSelectedItem(lastTargetedView);
455 targetView.setSelectedIndex(0);
458 btn_add.setVisible(targetView.isVisible());
463 * Updates the progress indicator with the specified message
466 * displayed message for the operation
468 * unique handle for this indicator
470 protected void updateProgressIndicator(String message, long id)
472 if (progressIndicator != null)
474 progressIndicator.setProgressBar(message, id);
479 * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
482 void fetchStructuresMetaData()
484 long startTime = System.currentTimeMillis();
485 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
486 .getStructureSummaryFields();
488 discoveredStructuresSet = new LinkedHashSet<>();
489 HashSet<String> errors = new HashSet<>();
491 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
494 for (SequenceI seq : selectedSequences)
497 FTSRestResponse resultList;
500 resultList = data.fetchStructuresMetaData(seq, wantedFields,
501 selectedFilterOpt, !chk_invertFilter.isSelected());
502 // null response means the FTSengine didn't yield a query for this
503 // consider designing a special exception if we really wanted to be
505 if (resultList == null)
509 } catch (Exception e)
512 errors.add(e.getMessage());
515 if (resultList.getSearchSummary() != null
516 && !resultList.getSearchSummary().isEmpty())
518 discoveredStructuresSet.addAll(resultList.getSearchSummary());
522 int noOfStructuresFound = 0;
523 String totalTime = (System.currentTimeMillis() - startTime)
525 if (discoveredStructuresSet != null
526 && !discoveredStructuresSet.isEmpty())
529 .setModel(data.getTableModel(discoveredStructuresSet));
531 noOfStructuresFound = discoveredStructuresSet.size();
532 lastDiscoveredStructuresSet = discoveredStructuresSet;
533 mainFrame.setTitle(MessageManager.formatMessage(
534 "label.structure_chooser_no_of_structures",
535 noOfStructuresFound, totalTime));
539 mainFrame.setTitle(MessageManager
540 .getString("label.structure_chooser_manual_association"));
541 if (errors.size() > 0)
543 StringBuilder errorMsg = new StringBuilder();
544 for (String error : errors)
546 errorMsg.append(error).append("\n");
548 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
549 MessageManager.getString("label.pdb_web-service_error"),
550 JvOptionPane.ERROR_MESSAGE);
555 protected void loadLocalCachedPDBEntries()
557 ArrayList<CachedPDB> entries = new ArrayList<>();
558 for (SequenceI seq : selectedSequences)
560 if (seq.getDatasetSequence() != null
561 && seq.getDatasetSequence().getAllPDBEntries() != null)
563 for (PDBEntry pdbEntry : seq.getDatasetSequence()
566 if (pdbEntry.getFile() != null)
568 entries.add(new CachedPDB(seq, pdbEntry));
573 cachedPDBExists = !entries.isEmpty();
574 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
575 tbl_local_pdb.setModel(tableModelx);
579 * Filters a given list of discovered structures based on supplied argument
581 * @param fieldToFilterBy
582 * the field to filter by
584 void filterResultSet(final String fieldToFilterBy)
586 Thread filterThread = new Thread(new Runnable()
592 long startTime = System.currentTimeMillis();
593 lbl_loading.setVisible(true);
594 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
595 .getStructureSummaryFields();
596 Collection<FTSData> filteredResponse = new HashSet<>();
597 HashSet<String> errors = new HashSet<>();
599 for (SequenceI seq : selectedSequences)
602 FTSRestResponse resultList;
605 resultList = data.selectFirstRankedQuery(seq,
606 discoveredStructuresSet, wantedFields, fieldToFilterBy,
607 !chk_invertFilter.isSelected());
609 } catch (Exception e)
612 errors.add(e.getMessage());
615 if (resultList.getSearchSummary() != null
616 && !resultList.getSearchSummary().isEmpty())
618 filteredResponse.addAll(resultList.getSearchSummary());
622 String totalTime = (System.currentTimeMillis() - startTime)
624 if (!filteredResponse.isEmpty())
626 final int filterResponseCount = filteredResponse.size();
627 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
628 reorderedStructuresSet.addAll(filteredResponse);
629 reorderedStructuresSet.addAll(discoveredStructuresSet);
631 .setModel(data.getTableModel(reorderedStructuresSet));
633 FTSRestResponse.configureTableColumn(getResultTable(),
634 wantedFields, tempUserPrefs);
635 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
636 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
637 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
638 // Update table selection model here
639 getResultTable().addRowSelectionInterval(0,
640 filterResponseCount - 1);
641 mainFrame.setTitle(MessageManager.formatMessage(
642 "label.structure_chooser_filter_time", totalTime));
646 mainFrame.setTitle(MessageManager.formatMessage(
647 "label.structure_chooser_filter_time", totalTime));
648 if (errors.size() > 0)
650 StringBuilder errorMsg = new StringBuilder();
651 for (String error : errors)
653 errorMsg.append(error).append("\n");
655 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
656 MessageManager.getString("label.pdb_web-service_error"),
657 JvOptionPane.ERROR_MESSAGE);
661 lbl_loading.setVisible(false);
663 validateSelections();
666 filterThread.start();
670 * Handles action event for btn_pdbFromFile
673 protected void pdbFromFile_actionPerformed()
675 // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
678 JalviewFileChooser chooser = new JalviewFileChooser(
679 Cache.getProperty("LAST_DIRECTORY"));
680 chooser.setFileView(new JalviewFileView());
681 chooser.setDialogTitle(
682 MessageManager.formatMessage("label.select_pdb_file_for",
683 selectedSequence.getDisplayId(false)));
684 chooser.setToolTipText(MessageManager.formatMessage(
685 "label.load_pdb_file_associate_with_sequence",
686 selectedSequence.getDisplayId(false)));
688 int value = chooser.showOpenDialog(null);
689 if (value == JalviewFileChooser.APPROVE_OPTION)
691 selectedPdbFileName = chooser.getSelectedFile().getPath();
692 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
693 boolean guessTFType = localPdbPaeMatrixFileName == null;
694 localPdbPaeMatrixFileName = guessPAEFilename();
695 guessTFType |= localPdbPaeMatrixFileName != null;
696 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
698 && alphaFold.search(new File(selectedPdbFileName).getName())
699 && !tempFacAsChanged)
701 // localPdbPaeMatrixFileName was null and now isn't and filename could
702 // well be AlphaFold and user hasn't adjusted the tempFacType
703 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
705 validateSelections();
710 * Handles action event for btn_pdbFromFile
713 protected void paeMatrixFile_actionPerformed()
715 File pdbFile = new File(selectedPdbFileName);
716 String setFile = Cache.getProperty("LAST_DIRECTORY");
717 if (localPdbPaeMatrixFileName != null)
719 File paeFile = new File(localPdbPaeMatrixFileName);
720 if (paeFile.exists())
721 setFile = paeFile.getAbsolutePath();
722 else if (paeFile.getParentFile().exists())
723 setFile = paeFile.getParentFile().getAbsolutePath();
727 String guess = guessPAEFilename();
731 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
732 chooser.setFileView(new JalviewFileView());
733 chooser.setDialogTitle(MessageManager.formatMessage(
734 "label.select_pae_matrix_file_for", pdbFile.getName()));
735 chooser.setToolTipText(MessageManager.formatMessage(
736 "label.load_pae_matrix_file_associate_with_structure",
739 int value = chooser.showOpenDialog(null);
740 if (value == JalviewFileChooser.APPROVE_OPTION)
742 localPdbPaeMatrixFileName = chooser.getSelectedFile().getPath();
743 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
745 validateAssociationFromFile();
748 private String guessPAEFilename()
750 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
751 || selectedPdbFileName.toLowerCase(Locale.ROOT)
754 String jsonExt = selectedPdbFileName.substring(0,
755 selectedPdbFileName.length() - 4) + ".json";
756 // AlphaFold naming scheme
757 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
758 "predicted_aligned_error");
759 // nf-core mode naming scheme
760 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
762 if (new File(guessFile1).exists())
766 else if (new File(jsonExt).exists())
770 else if (new File(guessFile2).exists())
779 * Populates the filter combo-box options dynamically depending on discovered
782 protected void populateFilterComboBox(boolean haveData,
783 boolean cachedPDBExist)
785 populateFilterComboBox(haveData, cachedPDBExist, null);
789 * Populates the filter combo-box options dynamically depending on discovered
792 protected void populateFilterComboBox(boolean haveData,
793 boolean cachedPDBExist, FilterOption lastSel)
797 * temporarily suspend the change listener behaviour
799 cmb_filterOption.removeItemListener(this);
801 cmb_filterOption.removeAllItems();
804 List<FilterOption> filters = data
805 .getAvailableFilterOptions(VIEWS_FILTER);
806 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
807 lastDiscoveredStructuresSet);
809 for (FilterOption filter : filters)
811 if (lastSel != null && filter.equals(lastSel))
816 cmb_filterOption.addItem(filter);
820 cmb_filterOption.addItem(
821 new FilterOption(MessageManager.getString("label.enter_pdb_id"),
822 "-", VIEWS_ENTER_ID, false, null));
823 cmb_filterOption.addItem(
824 new FilterOption(MessageManager.getString("label.from_file"),
825 "-", VIEWS_FROM_FILE, false, null));
826 if (canQueryTDB && notQueriedTDBYet)
828 btn_queryTDB.setVisible(true);
829 pnl_queryTDB.setVisible(true);
834 FilterOption cachedOption = new FilterOption(
835 MessageManager.getString("label.cached_structures"), "-",
836 VIEWS_LOCAL_PDB, false, null);
837 cmb_filterOption.addItem(cachedOption);
840 cmb_filterOption.setSelectedItem(cachedOption);
845 cmb_filterOption.setSelectedIndex(selSet);
847 cmb_filterOption.addItemListener(this);
851 * Updates the displayed view based on the selected filter option
853 protected void updateCurrentView()
855 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
858 if (lastSelected == selectedFilterOpt)
860 // don't need to do anything, probably
863 // otherwise, record selection
864 // and update the layout and dialog accordingly
865 lastSelected = selectedFilterOpt;
867 layout_switchableViews.show(pnl_switchableViews,
868 selectedFilterOpt.getView());
869 String filterTitle = mainFrame.getTitle();
870 mainFrame.setTitle(frameTitle);
871 chk_invertFilter.setVisible(false);
873 if (selectedFilterOpt.getView() == VIEWS_FILTER)
875 mainFrame.setTitle(filterTitle);
876 // TDB Query has no invert as yet
877 chk_invertFilter.setVisible(selectedFilterOpt
878 .getQuerySource() instanceof PDBStructureChooserQuerySource);
880 if (data != selectedFilterOpt.getQuerySource()
881 || data.needsRefetch(selectedFilterOpt))
883 data = selectedFilterOpt.getQuerySource();
884 // rebuild the views completely, since prefs will also change
890 filterResultSet(selectedFilterOpt.getValue());
893 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
894 || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
896 mainFrame.setTitle(MessageManager
897 .getString("label.structure_chooser_manual_association"));
898 idInputAssSeqPanel.loadCmbAssSeq();
899 fileChooserAssSeqPanel.loadCmbAssSeq();
901 validateSelections();
905 * Validates user selection and enables the 'Add' and 'New View' buttons if
906 * all parameters are correct (the Add button will only be visible if there is
907 * at least one existing structure viewer open). This basically means at least
908 * one structure selected and no error messages.
910 * The 'Superpose Structures' option is enabled if either more than one
911 * structure is selected, or the 'Add' to existing view option is enabled, and
912 * disabled if the only option is to open a new view of a single structure.
915 protected void validateSelections()
917 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
919 btn_add.setEnabled(false);
920 String currentView = selectedFilterOpt.getView();
921 int selectedCount = 0;
922 if (currentView == VIEWS_FILTER)
924 selectedCount = getResultTable().getSelectedRows().length;
925 if (selectedCount > 0)
927 btn_add.setEnabled(true);
930 else if (currentView == VIEWS_LOCAL_PDB)
932 selectedCount = tbl_local_pdb.getSelectedRows().length;
933 if (selectedCount > 0)
935 btn_add.setEnabled(true);
938 else if (currentView == VIEWS_ENTER_ID)
940 validateAssociationEnterPdb();
942 else if (currentView == VIEWS_FROM_FILE)
944 validateAssociationFromFile();
947 btn_newView.setEnabled(btn_add.isEnabled());
950 * enable 'Superpose' option if more than one structure is selected,
951 * or there are view(s) available to add structure(s) to
954 .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
958 protected boolean showPopupFor(int selectedRow, int x, int y)
960 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
962 String currentView = selectedFilterOpt.getView();
964 if (currentView == VIEWS_FILTER
965 && data instanceof ThreeDBStructureChooserQuerySource)
968 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
969 .getFTSDataFor(getResultTable(), selectedRow,
970 discoveredStructuresSet);
971 String pageUrl = row.getModelViewUrl();
972 JPopupMenu popup = new JPopupMenu("3D Beacons");
973 JMenuItem viewUrl = new JMenuItem("View model web page");
974 viewUrl.addActionListener(new ActionListener()
977 public void actionPerformed(ActionEvent e)
979 Desktop.showUrl(pageUrl);
983 SwingUtilities.invokeLater(new Runnable()
988 popup.show(getResultTable(), x, y);
993 // event not handled by us
998 * Validates inputs from the Manual PDB entry panel
1000 protected void validateAssociationEnterPdb()
1002 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
1003 .getCmb_assSeq().getSelectedItem();
1004 lbl_pdbManualFetchStatus.setIcon(errorImage);
1005 lbl_pdbManualFetchStatus.setToolTipText("");
1006 if (txt_search.getText().length() > 0)
1008 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1009 MessageManager.formatMessage("info.no_pdb_entry_found_for",
1010 txt_search.getText())));
1013 if (errorWarning.length() > 0)
1015 lbl_pdbManualFetchStatus.setIcon(warningImage);
1016 lbl_pdbManualFetchStatus.setToolTipText(
1017 JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1020 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1021 .equalsIgnoreCase("-Select Associated Seq-"))
1023 txt_search.setEnabled(true);
1024 if (isValidPBDEntry)
1026 btn_add.setEnabled(true);
1027 lbl_pdbManualFetchStatus.setToolTipText("");
1028 lbl_pdbManualFetchStatus.setIcon(goodImage);
1033 txt_search.setEnabled(false);
1034 lbl_pdbManualFetchStatus.setIcon(errorImage);
1039 * Validates inputs for the manual PDB file selection options
1041 protected void validateAssociationFromFile()
1043 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1044 .getCmb_assSeq().getSelectedItem();
1045 // lbl_fromFileStatus.setIcon(errorImage);
1046 String pdbFileString = "";
1047 String pdbFileTooltip = "";
1048 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1049 .getName().equalsIgnoreCase("-Select Associated Seq-")))
1051 btn_pdbFromFile.setEnabled(true);
1052 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1054 btn_add.setEnabled(true);
1055 // lbl_fromFileStatus.setIcon(goodImage);
1056 pdbFileString = new File(selectedPdbFileName).getName();
1057 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1058 setPdbOptionsEnabled(true);
1062 pdbFileString = MessageManager.getString("label.none");
1063 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1068 btn_pdbFromFile.setEnabled(false);
1069 // lbl_fromFileStatus.setIcon(errorImage);
1070 pdbFileString = MessageManager.getString("label.none");
1071 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1073 lbl_pdbFile.setText(pdbFileString);
1074 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1077 String paeFileString = "";
1078 String paeFileTooltip = "";
1079 if (localPdbPaeMatrixFileName != null
1080 && localPdbPaeMatrixFileName.length() > 0)
1082 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1083 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1088 paeFileString = MessageManager.getString("label.none");
1089 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1091 lbl_paeFile.setText(paeFileString);
1092 lbl_paeFile.setToolTipText(paeFileTooltip);
1096 protected void cmbAssSeqStateChanged()
1098 validateSelections();
1101 private FilterOption lastSelected = null;
1104 * Handles the state change event for the 'filter' combo-box and 'invert'
1108 protected void stateChanged(ItemEvent e)
1110 if (e.getSource() instanceof JCheckBox)
1112 updateCurrentView();
1116 if (e.getStateChange() == ItemEvent.SELECTED)
1118 updateCurrentView();
1125 * select structures for viewing by their PDB IDs
1128 * @return true if structures were found and marked as selected
1130 public boolean selectStructure(String... pdbids)
1132 boolean found = false;
1134 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1135 .getSelectedItem());
1136 String currentView = selectedFilterOpt.getView();
1137 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1138 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1140 if (restable == null)
1142 // can't select (enter PDB ID, or load file - need to also select which
1143 // sequence to associate with)
1147 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1148 for (int r = 0; r < restable.getRowCount(); r++)
1150 for (int p = 0; p < pdbids.length; p++)
1152 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1153 .equalsIgnoreCase(pdbids[p]))
1155 restable.setRowSelectionInterval(r, r);
1164 * Handles the 'New View' action
1167 protected void newView_ActionPerformed()
1169 targetView.setSelectedItem(null);
1170 showStructures(false);
1174 * Handles the 'Add to existing viewer' action
1177 protected void add_ActionPerformed()
1179 showStructures(false);
1183 * structure viewer opened by this dialog, or null
1185 private StructureViewer sViewer = null;
1187 public void showStructures(boolean waitUntilFinished)
1190 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1192 final int preferredHeight = pnl_filter.getHeight();
1194 Runnable viewStruc = new Runnable()
1199 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1200 .getSelectedItem());
1201 String currentView = selectedFilterOpt.getView();
1202 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1205 if (currentView == VIEWS_FILTER)
1207 int[] selectedRows = restable.getSelectedRows();
1208 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1209 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1210 pdbEntriesToView = data.collectSelectedRows(restable,
1211 selectedRows, selectedSeqsToView);
1213 SequenceI[] selectedSeqs = selectedSeqsToView
1214 .toArray(new SequenceI[selectedSeqsToView.size()]);
1215 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1218 else if (currentView == VIEWS_LOCAL_PDB)
1220 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1221 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1223 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1225 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1227 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1228 for (int row : selectedRows)
1230 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1231 .getModel()).getPDBEntryAt(row).getPdbEntry();
1233 pdbEntriesToView[count++] = pdbEntry;
1234 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1235 .getValueAt(row, refSeqColIndex);
1236 selectedSeqsToView.add(selectedSeq);
1238 SequenceI[] selectedSeqs = selectedSeqsToView
1239 .toArray(new SequenceI[selectedSeqsToView.size()]);
1240 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1243 else if (currentView == VIEWS_ENTER_ID)
1245 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1246 .getCmb_assSeq().getSelectedItem()).getSequence();
1247 if (userSelectedSeq != null)
1249 selectedSequence = userSelectedSeq;
1251 String pdbIdStr = txt_search.getText();
1252 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1253 if (pdbEntry == null)
1255 pdbEntry = new PDBEntry();
1256 if (pdbIdStr.split(":").length > 1)
1258 pdbEntry.setId(pdbIdStr.split(":")[0]);
1259 pdbEntry.setChainCode(
1260 pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1264 pdbEntry.setId(pdbIdStr);
1266 pdbEntry.setType(PDBEntry.Type.PDB);
1267 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1270 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1271 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1273 { selectedSequence });
1275 else if (currentView == VIEWS_FROM_FILE)
1277 StructureChooser sc = StructureChooser.this;
1278 TFType tft = (TFType) sc.combo_tempFacAs.getSelectedItem();
1279 String paeFilename = sc.localPdbPaeMatrixFileName;
1280 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1281 .getCmb_assSeq().getSelectedItem();
1282 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1283 if (userSelectedSeq != null)
1284 selectedSequence = userSelectedSeq;
1285 String pdbFilename = selectedPdbFileName;
1287 StructureChooser.openStructureFileForSequence(ssm, sc, ap,
1288 selectedSequence, true, pdbFilename, tft, paeFilename,
1291 SwingUtilities.invokeLater(new Runnable()
1296 closeAction(preferredHeight);
1297 mainFrame.dispose();
1302 Thread runner = new Thread(viewStruc);
1304 if (waitUntilFinished)
1306 while (sViewer == null ? runner.isAlive()
1307 : (sViewer.sview == null ? true
1308 : !sViewer.sview.hasMapping()))
1313 } catch (InterruptedException ie)
1322 * Answers a structure viewer (new or existing) configured to superimpose
1323 * added structures or not according to the user's choice
1328 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1330 Object sv = targetView.getSelectedItem();
1332 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1336 * Adds PDB structures to a new or existing structure viewer
1339 * @param pdbEntriesToView
1344 private StructureViewer launchStructureViewer(
1345 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1346 final AlignmentPanel alignPanel, SequenceI[] sequences)
1348 return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
1352 private StructureViewer launchStructureViewer(
1353 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1354 final AlignmentPanel alignPanel, SequenceI[] sequences,
1355 ViewerType viewerType)
1357 long progressId = sequences.hashCode();
1358 setProgressBar(MessageManager
1359 .getString("status.launching_3d_structure_viewer"), progressId);
1360 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1361 boolean superimpose = chk_superpose.isSelected();
1362 theViewer.setSuperpose(superimpose);
1365 * remember user's choice of superimpose or not
1367 Cache.setProperty(AUTOSUPERIMPOSE,
1368 Boolean.valueOf(superimpose).toString());
1370 setProgressBar(null, progressId);
1371 if (SiftsSettings.isMapWithSifts())
1373 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1375 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1376 // real PDB ID. For moment, we can also safely do this if there is already
1377 // a known mapping between the PDBEntry and the sequence.
1378 for (SequenceI seq : sequences)
1380 PDBEntry pdbe = pdbEntriesToView[p++];
1381 if (pdbe != null && pdbe.getFile() != null)
1383 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1384 if (smm != null && smm.length > 0)
1386 for (StructureMapping sm : smm)
1388 if (sm.getSequence() == seq)
1395 if (seq.getPrimaryDBRefs().isEmpty())
1397 seqsWithoutSourceDBRef.add(seq);
1401 if (!seqsWithoutSourceDBRef.isEmpty())
1403 int y = seqsWithoutSourceDBRef.size();
1404 setProgressBar(MessageManager.formatMessage(
1405 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1407 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1408 .toArray(new SequenceI[y]);
1409 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1410 dbRefFetcher.fetchDBRefs(true);
1412 setProgressBar("Fetch complete.", progressId); // todo i18n
1415 if (pdbEntriesToView.length > 1)
1418 MessageManager.getString(
1419 "status.fetching_3d_structures_for_selected_entries"),
1421 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
1426 setProgressBar(MessageManager.formatMessage(
1427 "status.fetching_3d_structures_for",
1428 pdbEntriesToView[0].getId()), progressId);
1429 // Can we pass a pre-computeMappinged pdbFile?
1430 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel,
1433 setProgressBar(null, progressId);
1434 // remember the last viewer we used...
1435 lastTargetedView = theViewer;
1440 * Populates the combo-box used in associating manually fetched structures to
1441 * a unique sequence when more than one sequence selection is made.
1444 protected void populateCmbAssociateSeqOptions(
1445 JComboBox<AssociateSeqOptions> cmb_assSeq,
1446 JLabel lbl_associateSeq)
1448 cmb_assSeq.removeAllItems();
1450 new AssociateSeqOptions("-Select Associated Seq-", null));
1451 lbl_associateSeq.setVisible(false);
1452 if (selectedSequences.length > 1)
1454 for (SequenceI seq : selectedSequences)
1456 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1461 String seqName = selectedSequence.getDisplayId(false);
1462 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1463 lbl_associateSeq.setText(seqName);
1464 lbl_associateSeq.setVisible(true);
1465 cmb_assSeq.setVisible(false);
1469 protected boolean isStructuresDiscovered()
1471 return discoveredStructuresSet != null
1472 && !discoveredStructuresSet.isEmpty();
1475 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1477 // Doing a search for "1" or "1c" is valuable?
1478 // Those work but are enormously slow.
1481 protected void txt_search_ActionPerformed()
1483 String text = txt_search.getText().trim();
1484 if (text.length() >= PDB_ID_MIN)
1491 errorWarning.setLength(0);
1492 isValidPBDEntry = false;
1493 if (text.length() > 0)
1495 // TODO move this pdb id search into the PDB specific
1497 // for moment, it will work fine as is because it is self-contained
1498 String searchTerm = text.toLowerCase(Locale.ROOT);
1499 searchTerm = searchTerm.split(":")[0];
1500 // System.out.println(">>>>> search term : " + searchTerm);
1501 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1502 FTSRestRequest pdbRequest = new FTSRestRequest();
1503 pdbRequest.setAllowEmptySeq(false);
1504 pdbRequest.setResponseSize(1);
1505 pdbRequest.setFieldToSearchBy("(pdb_id:");
1506 pdbRequest.setWantedFields(wantedFields);
1507 pdbRequest.setSearchTerm(searchTerm + ")");
1508 pdbRequest.setAssociatedSequence(selectedSequence);
1509 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1510 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1511 FTSRestResponse resultList;
1514 resultList = pdbRestClient.executeRequest(pdbRequest);
1515 } catch (Exception e)
1517 errorWarning.append(e.getMessage());
1521 validateSelections();
1523 if (resultList.getSearchSummary() != null
1524 && resultList.getSearchSummary().size() > 0)
1526 isValidPBDEntry = true;
1529 validateSelections();
1535 protected void tabRefresh()
1537 if (selectedSequences != null)
1539 lbl_loading.setVisible(true);
1540 Thread refreshThread = new Thread(new Runnable()
1545 fetchStructuresMetaData();
1546 // populateFilterComboBox(true, cachedPDBExists);
1549 ((FilterOption) cmb_filterOption.getSelectedItem())
1551 lbl_loading.setVisible(false);
1554 refreshThread.start();
1558 public class PDBEntryTableModel extends AbstractTableModel
1560 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1563 private List<CachedPDB> pdbEntries;
1565 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1567 this.pdbEntries = new ArrayList<>(pdbEntries);
1571 public String getColumnName(int columnIndex)
1573 return columns[columnIndex];
1577 public int getRowCount()
1579 return pdbEntries.size();
1583 public int getColumnCount()
1585 return columns.length;
1589 public boolean isCellEditable(int row, int column)
1595 public Object getValueAt(int rowIndex, int columnIndex)
1597 Object value = "??";
1598 CachedPDB entry = pdbEntries.get(rowIndex);
1599 switch (columnIndex)
1602 value = entry.getSequence();
1605 value = entry.getQualifiedId();
1608 value = entry.getPdbEntry().getChainCode() == null ? "_"
1609 : entry.getPdbEntry().getChainCode();
1612 value = entry.getPdbEntry().getType();
1615 value = entry.getPdbEntry().getFile();
1622 public Class<?> getColumnClass(int columnIndex)
1624 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1627 public CachedPDB getPDBEntryAt(int row)
1629 return pdbEntries.get(row);
1634 private class CachedPDB
1636 private SequenceI sequence;
1638 private PDBEntry pdbEntry;
1640 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1642 this.sequence = sequence;
1643 this.pdbEntry = pdbEntry;
1646 public String getQualifiedId()
1648 if (pdbEntry.hasProvider())
1650 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1652 return pdbEntry.toString();
1655 public SequenceI getSequence()
1660 public PDBEntry getPdbEntry()
1667 private IProgressIndicator progressBar;
1670 public void setProgressBar(String message, long id)
1672 if (!Platform.isHeadless())
1673 progressBar.setProgressBar(message, id);
1677 public void registerHandler(long id, IProgressIndicatorHandler handler)
1679 progressBar.registerHandler(id, handler);
1683 public boolean operationInProgress()
1685 return progressBar.operationInProgress();
1688 public JalviewStructureDisplayI getOpenedStructureViewer()
1690 return sViewer == null ? null : sViewer.sview;
1694 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1696 data.setDocFieldPrefs(newPrefs);
1702 * @return true when all initialisation threads have finished and dialog is
1705 public boolean isDialogVisible()
1707 return mainFrame != null && data != null && cmb_filterOption != null
1708 && mainFrame.isVisible()
1709 && cmb_filterOption.getSelectedItem() != null;
1714 * @return true if the 3D-Beacons query button will/has been displayed
1716 public boolean isCanQueryTDB()
1721 public boolean isNotQueriedTDBYet()
1723 return notQueriedTDBYet;
1727 * Open a single structure file for a given sequence
1729 public static void openStructureFileForSequence(
1730 StructureSelectionManager ssm, StructureChooser sc,
1731 AlignmentPanel ap, SequenceI seq, boolean prompt,
1732 String sFilename, TFType tft, String paeFilename,
1733 boolean doXferSettings)
1735 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1736 paeFilename, false, true, doXferSettings, null);
1739 public static void openStructureFileForSequence(
1740 StructureSelectionManager ssm, StructureChooser sc,
1741 AlignmentPanel ap, SequenceI seq, boolean prompt,
1742 String sFilename, TFType tft, String paeFilename,
1743 boolean forceHeadless, boolean showRefAnnotations,
1744 boolean doXferSettings, ViewerType viewerType)
1746 boolean headless = forceHeadless;
1751 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
1754 ssm = ap.getStructureSelectionManager();
1756 PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1757 sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
1758 tft, paeFilename, doXferSettings);
1760 // if headless, "false" in the sc constructor above will avoid GUI behaviour
1761 // in sc.launchStructureViewer()
1762 if (!headless && !(viewerType == null))
1763 sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1765 { seq }, viewerType);
1768 sc.mainFrame.dispose();
1770 if (showRefAnnotations)
1771 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1774 public static void showReferenceAnnotationsForSequence(AlignFrame af,
1777 AlignViewport av = af.getCurrentView();
1778 AlignmentI al = av.getAlignment();
1780 List<SequenceI> forSequences = new ArrayList<>();
1781 forSequences.add(sequence);
1782 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1783 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1785 final SequenceGroup selectionGroup = av.getSelectionGroup();
1786 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1787 for (AlignmentViewPanel ap : af.getAlignPanels())
1789 // required to readjust the height and position of the PAE
1791 ap.adjustAnnotationHeight();