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.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.seqfetcher.DbSourceProxy;
87 import jalview.ws.sifts.SiftsSettings;
90 * Provides the behaviors for the Structure chooser Panel
95 @SuppressWarnings("serial")
96 public class StructureChooser extends GStructureChooser
97 implements IProgressIndicator
99 private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
102 * warn user if need to fetch more than this many uniprot records at once
104 private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
106 private SequenceI selectedSequence;
108 private SequenceI[] selectedSequences;
110 private IProgressIndicator progressIndicator;
112 private Collection<FTSData> discoveredStructuresSet;
114 private StructureChooserQuerySource data;
117 protected FTSDataColumnPreferences getFTSDocFieldPrefs()
119 return data.getDocFieldPrefs();
122 private String selectedPdbFileName;
124 private TFType localPdbTempfacType;
126 private String localPdbPaeMatrixFileName;
128 private boolean isValidPBDEntry;
130 private boolean cachedPDBExists;
132 private Collection<FTSData> lastDiscoveredStructuresSet;
134 private boolean canQueryTDB = false;
136 private boolean notQueriedTDBYet = true;
138 List<SequenceI> seqsWithoutSourceDBRef = null;
140 private boolean showChooserGUI = true;
142 private static StructureViewer lastTargetedView = null;
144 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
147 this(selectedSeqs, selectedSeq, ap, true);
150 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
151 AlignmentPanel ap, boolean showGUI)
153 // which FTS engine to use
154 data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
158 this.selectedSequence = selectedSeq;
159 this.selectedSequences = selectedSeqs;
160 this.progressIndicator = (ap == null) ? null : ap.alignFrame;
161 this.showChooserGUI = showGUI;
167 * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
168 * least one structure are discovered.
170 private void populateSeqsWithoutSourceDBRef()
172 seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
173 boolean needCanonical = false;
174 for (SequenceI seq : selectedSequences)
178 int dbRef = ThreeDBStructureChooserQuerySource
179 .checkUniprotRefs(seq.getDBRefs());
184 // need to retrieve canonicals
185 needCanonical = true;
186 seqsWithoutSourceDBRef.add(seq);
190 // could be a sequence with pdb ref
191 if (seq.getAllPDBEntries() == null
192 || seq.getAllPDBEntries().size() == 0)
194 seqsWithoutSourceDBRef.add(seq);
200 // retrieve database refs for protein sequences
201 if (!seqsWithoutSourceDBRef.isEmpty())
206 // triggers display of the 'Query TDB' button
207 notQueriedTDBYet = true;
213 * Initializes parameters used by the Structure Chooser Panel
215 protected void init()
217 if (!Jalview.isHeadlessMode())
219 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
222 chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
223 btn_queryTDB.addActionListener(new ActionListener()
227 public void actionPerformed(ActionEvent e)
229 promptForTDBFetch(false);
233 Executors.defaultThreadFactory().newThread(new Runnable()
238 populateSeqsWithoutSourceDBRef();
239 initialStructureDiscovery();
247 private void initialStructureDiscovery()
249 // check which FTS engine to use
250 data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
252 // ensure a filter option is in force for search
253 populateFilterComboBox(true, cachedPDBExists);
255 // looks for any existing structures already loaded
256 // for the sequences (the cached ones)
257 // then queries the StructureChooserQuerySource to
258 // discover more structures.
260 // Possible optimisation is to only begin querying
261 // the structure chooser if there are no cached structures.
263 long startTime = System.currentTimeMillis();
264 updateProgressIndicator(
265 MessageManager.getString("status.loading_cached_pdb_entries"),
267 loadLocalCachedPDBEntries();
268 updateProgressIndicator(null, startTime);
269 updateProgressIndicator(
270 MessageManager.getString("status.searching_for_pdb_structures"),
272 fetchStructuresMetaData();
273 // revise filter options if no results were found
274 populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
275 discoverStructureViews();
276 updateProgressIndicator(null, startTime);
277 mainFrame.setVisible(showChooserGUI);
282 * raises dialog for Uniprot fetch followed by 3D beacons search
285 * - when true, don't ask, just fetch
287 public void promptForTDBFetch(boolean ignoreGui)
289 final long progressId = System.currentTimeMillis();
291 // final action after prompting and discovering db refs
292 final Runnable strucDiscovery = new Runnable()
297 mainFrame.setEnabled(false);
298 cmb_filterOption.setEnabled(false);
299 progressBar.setProgressBar(
300 MessageManager.getString("status.searching_3d_beacons"),
302 btn_queryTDB.setEnabled(false);
303 // TODO: warn if no accessions discovered
304 populateSeqsWithoutSourceDBRef();
305 // redo initial discovery - this time with 3d beacons
307 previousWantedFields = null;
308 lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
309 cmb_filterOption.setSelectedItem(null);
310 cachedPDBExists = false; // reset to initial
311 initialStructureDiscovery();
312 if (!isStructuresDiscovered())
314 progressBar.setProgressBar(MessageManager.getString(
315 "status.no_structures_discovered_from_3d_beacons"),
317 btn_queryTDB.setToolTipText(MessageManager.getString(
318 "status.no_structures_discovered_from_3d_beacons"));
319 btn_queryTDB.setEnabled(false);
320 pnl_queryTDB.setVisible(false);
324 cmb_filterOption.setSelectedIndex(0); // select 'best'
325 btn_queryTDB.setVisible(false);
326 pnl_queryTDB.setVisible(false);
327 progressBar.setProgressBar(null, progressId);
329 mainFrame.setEnabled(true);
330 cmb_filterOption.setEnabled(true);
334 final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
338 public void finished()
340 // filter has been selected, so we set flag to remove ourselves
341 notQueriedTDBYet = false;
342 // new thread to discover structures - via 3d beacons
343 Executors.defaultThreadFactory().newThread(strucDiscovery).start();
348 // fetch db refs if OK pressed
349 final Callable discoverCanonicalDBrefs = () -> {
350 btn_queryTDB.setEnabled(false);
351 populateSeqsWithoutSourceDBRef();
353 final int y = seqsWithoutSourceDBRef.size();
356 final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
357 .toArray(new SequenceI[y]);
358 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
359 progressBar, new DbSourceProxy[]
360 { new jalview.ws.dbsources.Uniprot() }, null, false);
361 dbRefFetcher.addListener(afterDbRefFetch);
362 // ideally this would also gracefully run with callbacks
364 dbRefFetcher.fetchDBRefs(true);
368 // call finished action directly
369 afterDbRefFetch.finished();
373 final Callable revertview = () -> {
374 if (lastSelected != null)
376 cmb_filterOption.setSelectedItem(lastSelected);
380 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
381 THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
382 Console.debug("Using Uniprot fetch threshold of " + threshold);
383 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
385 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
388 // need cancel and no to result in the discoverPDB action - mocked is
389 // 'cancel' TODO: mock should be OK
391 StructureChooser thisSC = this;
392 JvOptionPane.newOptionDialog(thisSC.getFrame())
393 .setResponseHandler(JvOptionPane.OK_OPTION,
394 discoverCanonicalDBrefs)
395 .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
396 .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
398 MessageManager.formatMessage(
399 "label.fetch_references_for_3dbeacons",
400 seqsWithoutSourceDBRef.size()),
401 MessageManager.getString("label.3dbeacons"),
402 JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
404 { MessageManager.getString("action.ok"),
405 MessageManager.getString("action.cancel") },
406 MessageManager.getString("action.ok"), false);
410 * Builds a drop-down choice list of existing structure viewers to which new
411 * structures may be added. If this list is empty then it, and the 'Add'
412 * button, are hidden.
414 private void discoverStructureViews()
416 if (Desktop.instance != null)
418 targetView.removeAllItems();
419 if (lastTargetedView != null && !lastTargetedView.isVisible())
421 lastTargetedView = null;
423 int linkedViewsAt = 0;
424 for (StructureViewerBase view : Desktop.instance
425 .getStructureViewers(null, null))
427 StructureViewer viewHandler = (lastTargetedView != null
428 && lastTargetedView.sview == view) ? lastTargetedView
429 : StructureViewer.reconfigure(view);
431 if (view.isLinkedWith(ap))
433 targetView.insertItemAt(viewHandler, linkedViewsAt++);
437 targetView.addItem(viewHandler);
442 * show option to Add to viewer if at least 1 viewer found
444 targetView.setVisible(false);
445 if (targetView.getItemCount() > 0)
447 targetView.setVisible(true);
448 if (lastTargetedView != null)
450 targetView.setSelectedItem(lastTargetedView);
454 targetView.setSelectedIndex(0);
457 btn_add.setVisible(targetView.isVisible());
462 * Updates the progress indicator with the specified message
465 * displayed message for the operation
467 * unique handle for this indicator
469 protected void updateProgressIndicator(String message, long id)
471 if (progressIndicator != null)
473 progressIndicator.setProgressBar(message, id);
478 * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
481 void fetchStructuresMetaData()
483 long startTime = System.currentTimeMillis();
484 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
485 .getStructureSummaryFields();
487 discoveredStructuresSet = new LinkedHashSet<>();
488 HashSet<String> errors = new HashSet<>();
490 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
493 for (SequenceI seq : selectedSequences)
496 FTSRestResponse resultList;
499 resultList = data.fetchStructuresMetaData(seq, wantedFields,
500 selectedFilterOpt, !chk_invertFilter.isSelected());
501 // null response means the FTSengine didn't yield a query for this
502 // consider designing a special exception if we really wanted to be
504 if (resultList == null)
508 } catch (Exception e)
511 errors.add(e.getMessage());
514 if (resultList.getSearchSummary() != null
515 && !resultList.getSearchSummary().isEmpty())
517 discoveredStructuresSet.addAll(resultList.getSearchSummary());
521 int noOfStructuresFound = 0;
522 String totalTime = (System.currentTimeMillis() - startTime)
524 if (discoveredStructuresSet != null
525 && !discoveredStructuresSet.isEmpty())
528 .setModel(data.getTableModel(discoveredStructuresSet));
530 noOfStructuresFound = discoveredStructuresSet.size();
531 lastDiscoveredStructuresSet = discoveredStructuresSet;
532 mainFrame.setTitle(MessageManager.formatMessage(
533 "label.structure_chooser_no_of_structures",
534 noOfStructuresFound, totalTime));
538 mainFrame.setTitle(MessageManager
539 .getString("label.structure_chooser_manual_association"));
540 if (errors.size() > 0)
542 StringBuilder errorMsg = new StringBuilder();
543 for (String error : errors)
545 errorMsg.append(error).append("\n");
547 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
548 MessageManager.getString("label.pdb_web-service_error"),
549 JvOptionPane.ERROR_MESSAGE);
554 protected void loadLocalCachedPDBEntries()
556 ArrayList<CachedPDB> entries = new ArrayList<>();
557 for (SequenceI seq : selectedSequences)
559 if (seq.getDatasetSequence() != null
560 && seq.getDatasetSequence().getAllPDBEntries() != null)
562 for (PDBEntry pdbEntry : seq.getDatasetSequence()
565 if (pdbEntry.getFile() != null)
567 entries.add(new CachedPDB(seq, pdbEntry));
572 cachedPDBExists = !entries.isEmpty();
573 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
574 tbl_local_pdb.setModel(tableModelx);
578 * Filters a given list of discovered structures based on supplied argument
580 * @param fieldToFilterBy
581 * the field to filter by
583 void filterResultSet(final String fieldToFilterBy)
585 Thread filterThread = new Thread(new Runnable()
591 long startTime = System.currentTimeMillis();
592 lbl_loading.setVisible(true);
593 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
594 .getStructureSummaryFields();
595 Collection<FTSData> filteredResponse = new HashSet<>();
596 HashSet<String> errors = new HashSet<>();
598 for (SequenceI seq : selectedSequences)
601 FTSRestResponse resultList;
604 resultList = data.selectFirstRankedQuery(seq,
605 discoveredStructuresSet, wantedFields, fieldToFilterBy,
606 !chk_invertFilter.isSelected());
608 } catch (Exception e)
611 errors.add(e.getMessage());
614 if (resultList.getSearchSummary() != null
615 && !resultList.getSearchSummary().isEmpty())
617 filteredResponse.addAll(resultList.getSearchSummary());
621 String totalTime = (System.currentTimeMillis() - startTime)
623 if (!filteredResponse.isEmpty())
625 final int filterResponseCount = filteredResponse.size();
626 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
627 reorderedStructuresSet.addAll(filteredResponse);
628 reorderedStructuresSet.addAll(discoveredStructuresSet);
630 .setModel(data.getTableModel(reorderedStructuresSet));
632 FTSRestResponse.configureTableColumn(getResultTable(),
633 wantedFields, tempUserPrefs);
634 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
635 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
636 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
637 // Update table selection model here
638 getResultTable().addRowSelectionInterval(0,
639 filterResponseCount - 1);
640 mainFrame.setTitle(MessageManager.formatMessage(
641 "label.structure_chooser_filter_time", totalTime));
645 mainFrame.setTitle(MessageManager.formatMessage(
646 "label.structure_chooser_filter_time", totalTime));
647 if (errors.size() > 0)
649 StringBuilder errorMsg = new StringBuilder();
650 for (String error : errors)
652 errorMsg.append(error).append("\n");
654 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
655 MessageManager.getString("label.pdb_web-service_error"),
656 JvOptionPane.ERROR_MESSAGE);
660 lbl_loading.setVisible(false);
662 validateSelections();
665 filterThread.start();
669 * Handles action event for btn_pdbFromFile
672 protected void pdbFromFile_actionPerformed()
674 // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
677 JalviewFileChooser chooser = new JalviewFileChooser(
678 Cache.getProperty("LAST_DIRECTORY"));
679 chooser.setFileView(new JalviewFileView());
680 chooser.setDialogTitle(
681 MessageManager.formatMessage("label.select_pdb_file_for",
682 selectedSequence.getDisplayId(false)));
683 chooser.setToolTipText(MessageManager.formatMessage(
684 "label.load_pdb_file_associate_with_sequence",
685 selectedSequence.getDisplayId(false)));
687 int value = chooser.showOpenDialog(null);
688 if (value == JalviewFileChooser.APPROVE_OPTION)
690 selectedPdbFileName = chooser.getSelectedFile().getPath();
691 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
692 boolean guessTFType = localPdbPaeMatrixFileName == null;
693 localPdbPaeMatrixFileName = guessPAEFilename();
694 guessTFType |= localPdbPaeMatrixFileName != null;
695 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
697 && alphaFold.search(new File(selectedPdbFileName).getName())
698 && !tempFacAsChanged)
700 // localPdbPaeMatrixFileName was null and now isn't and filename could
701 // well be AlphaFold and user hasn't adjusted the tempFacType
702 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
704 validateSelections();
709 * Handles action event for btn_pdbFromFile
712 protected void paeMatrixFile_actionPerformed()
714 File pdbFile = new File(selectedPdbFileName);
715 String setFile = Cache.getProperty("LAST_DIRECTORY");
716 if (localPdbPaeMatrixFileName != null)
718 File paeFile = new File(localPdbPaeMatrixFileName);
719 if (paeFile.exists())
720 setFile = paeFile.getAbsolutePath();
721 else if (paeFile.getParentFile().exists())
722 setFile = paeFile.getParentFile().getAbsolutePath();
726 String guess = guessPAEFilename();
730 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
731 chooser.setFileView(new JalviewFileView());
732 chooser.setDialogTitle(MessageManager.formatMessage(
733 "label.select_pae_matrix_file_for", pdbFile.getName()));
734 chooser.setToolTipText(MessageManager.formatMessage(
735 "label.load_pae_matrix_file_associate_with_structure",
738 int value = chooser.showOpenDialog(null);
739 if (value == JalviewFileChooser.APPROVE_OPTION)
741 localPdbPaeMatrixFileName = chooser.getSelectedFile().getPath();
742 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
744 validateAssociationFromFile();
747 private String guessPAEFilename()
749 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
750 || selectedPdbFileName.toLowerCase(Locale.ROOT)
753 String jsonExt = selectedPdbFileName.substring(0,
754 selectedPdbFileName.length() - 4) + ".json";
755 // AlphaFold naming scheme
756 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
757 "predicted_aligned_error");
758 // nf-core mode naming scheme
759 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
761 if (new File(guessFile1).exists())
765 else if (new File(jsonExt).exists())
769 else if (new File(guessFile2).exists())
778 * Populates the filter combo-box options dynamically depending on discovered
781 protected void populateFilterComboBox(boolean haveData,
782 boolean cachedPDBExist)
784 populateFilterComboBox(haveData, cachedPDBExist, null);
788 * Populates the filter combo-box options dynamically depending on discovered
791 protected void populateFilterComboBox(boolean haveData,
792 boolean cachedPDBExist, FilterOption lastSel)
796 * temporarily suspend the change listener behaviour
798 cmb_filterOption.removeItemListener(this);
800 cmb_filterOption.removeAllItems();
803 List<FilterOption> filters = data
804 .getAvailableFilterOptions(VIEWS_FILTER);
805 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
806 lastDiscoveredStructuresSet);
808 for (FilterOption filter : filters)
810 if (lastSel != null && filter.equals(lastSel))
815 cmb_filterOption.addItem(filter);
819 cmb_filterOption.addItem(
820 new FilterOption(MessageManager.getString("label.enter_pdb_id"),
821 "-", VIEWS_ENTER_ID, false, null));
822 cmb_filterOption.addItem(
823 new FilterOption(MessageManager.getString("label.from_file"),
824 "-", VIEWS_FROM_FILE, false, null));
825 if (canQueryTDB && notQueriedTDBYet)
827 btn_queryTDB.setVisible(true);
828 pnl_queryTDB.setVisible(true);
833 FilterOption cachedOption = new FilterOption(
834 MessageManager.getString("label.cached_structures"), "-",
835 VIEWS_LOCAL_PDB, false, null);
836 cmb_filterOption.addItem(cachedOption);
839 cmb_filterOption.setSelectedItem(cachedOption);
844 cmb_filterOption.setSelectedIndex(selSet);
846 cmb_filterOption.addItemListener(this);
850 * Updates the displayed view based on the selected filter option
852 protected void updateCurrentView()
854 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
857 if (lastSelected == selectedFilterOpt)
859 // don't need to do anything, probably
862 // otherwise, record selection
863 // and update the layout and dialog accordingly
864 lastSelected = selectedFilterOpt;
866 layout_switchableViews.show(pnl_switchableViews,
867 selectedFilterOpt.getView());
868 String filterTitle = mainFrame.getTitle();
869 mainFrame.setTitle(frameTitle);
870 chk_invertFilter.setVisible(false);
872 if (selectedFilterOpt.getView() == VIEWS_FILTER)
874 mainFrame.setTitle(filterTitle);
875 // TDB Query has no invert as yet
876 chk_invertFilter.setVisible(selectedFilterOpt
877 .getQuerySource() instanceof PDBStructureChooserQuerySource);
879 if (data != selectedFilterOpt.getQuerySource()
880 || data.needsRefetch(selectedFilterOpt))
882 data = selectedFilterOpt.getQuerySource();
883 // rebuild the views completely, since prefs will also change
889 filterResultSet(selectedFilterOpt.getValue());
892 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
893 || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
895 mainFrame.setTitle(MessageManager
896 .getString("label.structure_chooser_manual_association"));
897 idInputAssSeqPanel.loadCmbAssSeq();
898 fileChooserAssSeqPanel.loadCmbAssSeq();
900 validateSelections();
904 * Validates user selection and enables the 'Add' and 'New View' buttons if
905 * all parameters are correct (the Add button will only be visible if there is
906 * at least one existing structure viewer open). This basically means at least
907 * one structure selected and no error messages.
909 * The 'Superpose Structures' option is enabled if either more than one
910 * structure is selected, or the 'Add' to existing view option is enabled, and
911 * disabled if the only option is to open a new view of a single structure.
914 protected void validateSelections()
916 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
918 btn_add.setEnabled(false);
919 String currentView = selectedFilterOpt.getView();
920 int selectedCount = 0;
921 if (currentView == VIEWS_FILTER)
923 selectedCount = getResultTable().getSelectedRows().length;
924 if (selectedCount > 0)
926 btn_add.setEnabled(true);
929 else if (currentView == VIEWS_LOCAL_PDB)
931 selectedCount = tbl_local_pdb.getSelectedRows().length;
932 if (selectedCount > 0)
934 btn_add.setEnabled(true);
937 else if (currentView == VIEWS_ENTER_ID)
939 validateAssociationEnterPdb();
941 else if (currentView == VIEWS_FROM_FILE)
943 validateAssociationFromFile();
946 btn_newView.setEnabled(btn_add.isEnabled());
949 * enable 'Superpose' option if more than one structure is selected,
950 * or there are view(s) available to add structure(s) to
953 .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
957 protected boolean showPopupFor(int selectedRow, int x, int y)
959 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
961 String currentView = selectedFilterOpt.getView();
963 if (currentView == VIEWS_FILTER
964 && data instanceof ThreeDBStructureChooserQuerySource)
967 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
968 .getFTSDataFor(getResultTable(), selectedRow,
969 discoveredStructuresSet);
970 String pageUrl = row.getModelViewUrl();
971 JPopupMenu popup = new JPopupMenu("3D Beacons");
972 JMenuItem viewUrl = new JMenuItem("View model web page");
973 viewUrl.addActionListener(new ActionListener()
976 public void actionPerformed(ActionEvent e)
978 Desktop.showUrl(pageUrl);
982 SwingUtilities.invokeLater(new Runnable()
987 popup.show(getResultTable(), x, y);
992 // event not handled by us
997 * Validates inputs from the Manual PDB entry panel
999 protected void validateAssociationEnterPdb()
1001 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
1002 .getCmb_assSeq().getSelectedItem();
1003 lbl_pdbManualFetchStatus.setIcon(errorImage);
1004 lbl_pdbManualFetchStatus.setToolTipText("");
1005 if (txt_search.getText().length() > 0)
1007 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1008 MessageManager.formatMessage("info.no_pdb_entry_found_for",
1009 txt_search.getText())));
1012 if (errorWarning.length() > 0)
1014 lbl_pdbManualFetchStatus.setIcon(warningImage);
1015 lbl_pdbManualFetchStatus.setToolTipText(
1016 JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1019 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1020 .equalsIgnoreCase("-Select Associated Seq-"))
1022 txt_search.setEnabled(true);
1023 if (isValidPBDEntry)
1025 btn_add.setEnabled(true);
1026 lbl_pdbManualFetchStatus.setToolTipText("");
1027 lbl_pdbManualFetchStatus.setIcon(goodImage);
1032 txt_search.setEnabled(false);
1033 lbl_pdbManualFetchStatus.setIcon(errorImage);
1038 * Validates inputs for the manual PDB file selection options
1040 protected void validateAssociationFromFile()
1042 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1043 .getCmb_assSeq().getSelectedItem();
1044 // lbl_fromFileStatus.setIcon(errorImage);
1045 String pdbFileString = "";
1046 String pdbFileTooltip = "";
1047 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1048 .getName().equalsIgnoreCase("-Select Associated Seq-")))
1050 btn_pdbFromFile.setEnabled(true);
1051 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1053 btn_add.setEnabled(true);
1054 // lbl_fromFileStatus.setIcon(goodImage);
1055 pdbFileString = new File(selectedPdbFileName).getName();
1056 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1057 setPdbOptionsEnabled(true);
1061 pdbFileString = MessageManager.getString("label.none");
1062 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1067 btn_pdbFromFile.setEnabled(false);
1068 // lbl_fromFileStatus.setIcon(errorImage);
1069 pdbFileString = MessageManager.getString("label.none");
1070 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1072 lbl_pdbFile.setText(pdbFileString);
1073 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1076 String paeFileString = "";
1077 String paeFileTooltip = "";
1078 if (localPdbPaeMatrixFileName != null
1079 && localPdbPaeMatrixFileName.length() > 0)
1081 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1082 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1087 paeFileString = MessageManager.getString("label.none");
1088 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1090 lbl_paeFile.setText(paeFileString);
1091 lbl_paeFile.setToolTipText(paeFileTooltip);
1095 protected void cmbAssSeqStateChanged()
1097 validateSelections();
1100 private FilterOption lastSelected = null;
1103 * Handles the state change event for the 'filter' combo-box and 'invert'
1107 protected void stateChanged(ItemEvent e)
1109 if (e.getSource() instanceof JCheckBox)
1111 updateCurrentView();
1115 if (e.getStateChange() == ItemEvent.SELECTED)
1117 updateCurrentView();
1124 * select structures for viewing by their PDB IDs
1127 * @return true if structures were found and marked as selected
1129 public boolean selectStructure(String... pdbids)
1131 boolean found = false;
1133 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1134 .getSelectedItem());
1135 String currentView = selectedFilterOpt.getView();
1136 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1137 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1139 if (restable == null)
1141 // can't select (enter PDB ID, or load file - need to also select which
1142 // sequence to associate with)
1146 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1147 for (int r = 0; r < restable.getRowCount(); r++)
1149 for (int p = 0; p < pdbids.length; p++)
1151 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1152 .equalsIgnoreCase(pdbids[p]))
1154 restable.setRowSelectionInterval(r, r);
1163 * Handles the 'New View' action
1166 protected void newView_ActionPerformed()
1168 targetView.setSelectedItem(null);
1169 showStructures(false);
1173 * Handles the 'Add to existing viewer' action
1176 protected void add_ActionPerformed()
1178 showStructures(false);
1182 * structure viewer opened by this dialog, or null
1184 private StructureViewer sViewer = null;
1186 public void showStructures(boolean waitUntilFinished)
1189 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1191 final int preferredHeight = pnl_filter.getHeight();
1193 Runnable viewStruc = new Runnable()
1198 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1199 .getSelectedItem());
1200 String currentView = selectedFilterOpt.getView();
1201 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1204 if (currentView == VIEWS_FILTER)
1206 int[] selectedRows = restable.getSelectedRows();
1207 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1208 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1209 pdbEntriesToView = data.collectSelectedRows(restable,
1210 selectedRows, selectedSeqsToView);
1212 SequenceI[] selectedSeqs = selectedSeqsToView
1213 .toArray(new SequenceI[selectedSeqsToView.size()]);
1214 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1217 else if (currentView == VIEWS_LOCAL_PDB)
1219 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1220 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1222 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1224 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1226 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1227 for (int row : selectedRows)
1229 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1230 .getModel()).getPDBEntryAt(row).getPdbEntry();
1232 pdbEntriesToView[count++] = pdbEntry;
1233 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1234 .getValueAt(row, refSeqColIndex);
1235 selectedSeqsToView.add(selectedSeq);
1237 SequenceI[] selectedSeqs = selectedSeqsToView
1238 .toArray(new SequenceI[selectedSeqsToView.size()]);
1239 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1242 else if (currentView == VIEWS_ENTER_ID)
1244 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1245 .getCmb_assSeq().getSelectedItem()).getSequence();
1246 if (userSelectedSeq != null)
1248 selectedSequence = userSelectedSeq;
1250 String pdbIdStr = txt_search.getText();
1251 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1252 if (pdbEntry == null)
1254 pdbEntry = new PDBEntry();
1255 if (pdbIdStr.split(":").length > 1)
1257 pdbEntry.setId(pdbIdStr.split(":")[0]);
1258 pdbEntry.setChainCode(
1259 pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1263 pdbEntry.setId(pdbIdStr);
1265 pdbEntry.setType(PDBEntry.Type.PDB);
1266 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1269 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1270 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1272 { selectedSequence });
1274 else if (currentView == VIEWS_FROM_FILE)
1276 StructureChooser sc = StructureChooser.this;
1277 TFType tft = (TFType) sc.combo_tempFacAs.getSelectedItem();
1278 String paeFilename = sc.localPdbPaeMatrixFileName;
1279 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1280 .getCmb_assSeq().getSelectedItem();
1281 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1282 if (userSelectedSeq != null)
1283 selectedSequence = userSelectedSeq;
1284 String pdbFilename = selectedPdbFileName;
1286 StructureChooser.openStructureFileForSequence(ssm, sc, ap,
1287 selectedSequence, true, pdbFilename, tft, paeFilename,
1290 SwingUtilities.invokeLater(new Runnable()
1295 closeAction(preferredHeight);
1296 mainFrame.dispose();
1301 Thread runner = new Thread(viewStruc);
1303 if (waitUntilFinished)
1305 while (sViewer == null ? runner.isAlive()
1306 : (sViewer.sview == null ? true
1307 : !sViewer.sview.hasMapping()))
1312 } catch (InterruptedException ie)
1321 * Answers a structure viewer (new or existing) configured to superimpose
1322 * added structures or not according to the user's choice
1327 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1329 Object sv = targetView.getSelectedItem();
1331 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1335 * Adds PDB structures to a new or existing structure viewer
1338 * @param pdbEntriesToView
1343 private StructureViewer launchStructureViewer(
1344 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1345 final AlignmentPanel alignPanel, SequenceI[] sequences)
1347 long progressId = sequences.hashCode();
1348 setProgressBar(MessageManager
1349 .getString("status.launching_3d_structure_viewer"), progressId);
1350 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1351 boolean superimpose = chk_superpose.isSelected();
1352 theViewer.setSuperpose(superimpose);
1355 * remember user's choice of superimpose or not
1357 Cache.setProperty(AUTOSUPERIMPOSE,
1358 Boolean.valueOf(superimpose).toString());
1360 setProgressBar(null, progressId);
1361 if (SiftsSettings.isMapWithSifts())
1363 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1365 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1366 // real PDB ID. For moment, we can also safely do this if there is already
1367 // a known mapping between the PDBEntry and the sequence.
1368 for (SequenceI seq : sequences)
1370 PDBEntry pdbe = pdbEntriesToView[p++];
1371 if (pdbe != null && pdbe.getFile() != null)
1373 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1374 if (smm != null && smm.length > 0)
1376 for (StructureMapping sm : smm)
1378 if (sm.getSequence() == seq)
1385 if (seq.getPrimaryDBRefs().isEmpty())
1387 seqsWithoutSourceDBRef.add(seq);
1391 if (!seqsWithoutSourceDBRef.isEmpty())
1393 int y = seqsWithoutSourceDBRef.size();
1394 setProgressBar(MessageManager.formatMessage(
1395 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1397 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1398 .toArray(new SequenceI[y]);
1399 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1400 dbRefFetcher.fetchDBRefs(true);
1402 setProgressBar("Fetch complete.", progressId); // todo i18n
1405 if (pdbEntriesToView.length > 1)
1408 MessageManager.getString(
1409 "status.fetching_3d_structures_for_selected_entries"),
1411 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
1415 setProgressBar(MessageManager.formatMessage(
1416 "status.fetching_3d_structures_for",
1417 pdbEntriesToView[0].getId()), progressId);
1418 // Can we pass a pre-computeMappinged pdbFile?
1419 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
1421 setProgressBar(null, progressId);
1422 // remember the last viewer we used...
1423 lastTargetedView = theViewer;
1428 * Populates the combo-box used in associating manually fetched structures to
1429 * a unique sequence when more than one sequence selection is made.
1432 protected void populateCmbAssociateSeqOptions(
1433 JComboBox<AssociateSeqOptions> cmb_assSeq,
1434 JLabel lbl_associateSeq)
1436 cmb_assSeq.removeAllItems();
1438 new AssociateSeqOptions("-Select Associated Seq-", null));
1439 lbl_associateSeq.setVisible(false);
1440 if (selectedSequences.length > 1)
1442 for (SequenceI seq : selectedSequences)
1444 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1449 String seqName = selectedSequence.getDisplayId(false);
1450 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1451 lbl_associateSeq.setText(seqName);
1452 lbl_associateSeq.setVisible(true);
1453 cmb_assSeq.setVisible(false);
1457 protected boolean isStructuresDiscovered()
1459 return discoveredStructuresSet != null
1460 && !discoveredStructuresSet.isEmpty();
1463 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1465 // Doing a search for "1" or "1c" is valuable?
1466 // Those work but are enormously slow.
1469 protected void txt_search_ActionPerformed()
1471 String text = txt_search.getText().trim();
1472 if (text.length() >= PDB_ID_MIN)
1479 errorWarning.setLength(0);
1480 isValidPBDEntry = false;
1481 if (text.length() > 0)
1483 // TODO move this pdb id search into the PDB specific
1485 // for moment, it will work fine as is because it is self-contained
1486 String searchTerm = text.toLowerCase(Locale.ROOT);
1487 searchTerm = searchTerm.split(":")[0];
1488 // System.out.println(">>>>> search term : " + searchTerm);
1489 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1490 FTSRestRequest pdbRequest = new FTSRestRequest();
1491 pdbRequest.setAllowEmptySeq(false);
1492 pdbRequest.setResponseSize(1);
1493 pdbRequest.setFieldToSearchBy("(pdb_id:");
1494 pdbRequest.setWantedFields(wantedFields);
1495 pdbRequest.setSearchTerm(searchTerm + ")");
1496 pdbRequest.setAssociatedSequence(selectedSequence);
1497 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1498 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1499 FTSRestResponse resultList;
1502 resultList = pdbRestClient.executeRequest(pdbRequest);
1503 } catch (Exception e)
1505 errorWarning.append(e.getMessage());
1509 validateSelections();
1511 if (resultList.getSearchSummary() != null
1512 && resultList.getSearchSummary().size() > 0)
1514 isValidPBDEntry = true;
1517 validateSelections();
1523 protected void tabRefresh()
1525 if (selectedSequences != null)
1527 lbl_loading.setVisible(true);
1528 Thread refreshThread = new Thread(new Runnable()
1533 fetchStructuresMetaData();
1534 // populateFilterComboBox(true, cachedPDBExists);
1537 ((FilterOption) cmb_filterOption.getSelectedItem())
1539 lbl_loading.setVisible(false);
1542 refreshThread.start();
1546 public class PDBEntryTableModel extends AbstractTableModel
1548 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1551 private List<CachedPDB> pdbEntries;
1553 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1555 this.pdbEntries = new ArrayList<>(pdbEntries);
1559 public String getColumnName(int columnIndex)
1561 return columns[columnIndex];
1565 public int getRowCount()
1567 return pdbEntries.size();
1571 public int getColumnCount()
1573 return columns.length;
1577 public boolean isCellEditable(int row, int column)
1583 public Object getValueAt(int rowIndex, int columnIndex)
1585 Object value = "??";
1586 CachedPDB entry = pdbEntries.get(rowIndex);
1587 switch (columnIndex)
1590 value = entry.getSequence();
1593 value = entry.getQualifiedId();
1596 value = entry.getPdbEntry().getChainCode() == null ? "_"
1597 : entry.getPdbEntry().getChainCode();
1600 value = entry.getPdbEntry().getType();
1603 value = entry.getPdbEntry().getFile();
1610 public Class<?> getColumnClass(int columnIndex)
1612 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1615 public CachedPDB getPDBEntryAt(int row)
1617 return pdbEntries.get(row);
1622 private class CachedPDB
1624 private SequenceI sequence;
1626 private PDBEntry pdbEntry;
1628 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1630 this.sequence = sequence;
1631 this.pdbEntry = pdbEntry;
1634 public String getQualifiedId()
1636 if (pdbEntry.hasProvider())
1638 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1640 return pdbEntry.toString();
1643 public SequenceI getSequence()
1648 public PDBEntry getPdbEntry()
1655 private IProgressIndicator progressBar;
1658 public void setProgressBar(String message, long id)
1660 if (!Platform.isHeadless())
1661 progressBar.setProgressBar(message, id);
1665 public void registerHandler(long id, IProgressIndicatorHandler handler)
1667 progressBar.registerHandler(id, handler);
1671 public boolean operationInProgress()
1673 return progressBar.operationInProgress();
1676 public JalviewStructureDisplayI getOpenedStructureViewer()
1678 return sViewer == null ? null : sViewer.sview;
1682 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1684 data.setDocFieldPrefs(newPrefs);
1690 * @return true when all initialisation threads have finished and dialog is
1693 public boolean isDialogVisible()
1695 return mainFrame != null && data != null && cmb_filterOption != null
1696 && mainFrame.isVisible()
1697 && cmb_filterOption.getSelectedItem() != null;
1702 * @return true if the 3D-Beacons query button will/has been displayed
1704 public boolean isCanQueryTDB()
1709 public boolean isNotQueriedTDBYet()
1711 return notQueriedTDBYet;
1715 * Open a single structure file for a given sequence
1717 public static void openStructureFileForSequence(
1718 StructureSelectionManager ssm, StructureChooser sc,
1719 AlignmentPanel ap, SequenceI seq, boolean prompt,
1720 String sFilename, TFType tft, String paeFilename,
1721 boolean doXferSettings)
1723 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1724 paeFilename, false, true, doXferSettings);
1727 public static void openStructureFileForSequence(
1728 StructureSelectionManager ssm, StructureChooser sc,
1729 AlignmentPanel ap, SequenceI seq, boolean prompt,
1730 String sFilename, TFType tft, String paeFilename,
1731 boolean forceHeadless, boolean showAnnotations,
1732 boolean doXferSettings)
1734 boolean headless = forceHeadless;
1739 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
1742 ssm = ap.getStructureSelectionManager();
1744 PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1745 sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
1746 tft, paeFilename, doXferSettings);
1748 // if headless, "false" in the sc constructor above will avoid GUI behaviour
1749 // in sc.launchStructureViewer()
1750 sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1755 sc.mainFrame.dispose();
1757 if (showAnnotations)
1758 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1761 public static void showReferenceAnnotationsForSequence(AlignFrame af,
1764 AlignViewport av = af.getCurrentView();
1765 AlignmentI al = av.getAlignment();
1767 List<SequenceI> forSequences = new ArrayList<>();
1768 forSequences.add(sequence);
1769 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1770 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1772 final SequenceGroup selectionGroup = av.getSelectionGroup();
1773 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1774 for (AlignmentViewPanel ap : af.getAlignPanels())
1776 // required to readjust the height and position of the PAE
1778 ap.adjustAnnotationHeight();