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);
1289 SwingUtilities.invokeLater(new Runnable()
1294 closeAction(preferredHeight);
1295 mainFrame.dispose();
1300 Thread runner = new Thread(viewStruc);
1302 if (waitUntilFinished)
1304 while (sViewer == null ? runner.isAlive()
1305 : (sViewer.sview == null ? true
1306 : !sViewer.sview.hasMapping()))
1311 } catch (InterruptedException ie)
1320 * Answers a structure viewer (new or existing) configured to superimpose
1321 * added structures or not according to the user's choice
1326 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1328 Object sv = targetView.getSelectedItem();
1330 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1334 * Adds PDB structures to a new or existing structure viewer
1337 * @param pdbEntriesToView
1342 private StructureViewer launchStructureViewer(
1343 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1344 final AlignmentPanel alignPanel, SequenceI[] sequences)
1346 long progressId = sequences.hashCode();
1347 setProgressBar(MessageManager
1348 .getString("status.launching_3d_structure_viewer"), progressId);
1349 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1350 boolean superimpose = chk_superpose.isSelected();
1351 theViewer.setSuperpose(superimpose);
1354 * remember user's choice of superimpose or not
1356 Cache.setProperty(AUTOSUPERIMPOSE,
1357 Boolean.valueOf(superimpose).toString());
1359 setProgressBar(null, progressId);
1360 if (SiftsSettings.isMapWithSifts())
1362 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1364 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1365 // real PDB ID. For moment, we can also safely do this if there is already
1366 // a known mapping between the PDBEntry and the sequence.
1367 for (SequenceI seq : sequences)
1369 PDBEntry pdbe = pdbEntriesToView[p++];
1370 if (pdbe != null && pdbe.getFile() != null)
1372 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1373 if (smm != null && smm.length > 0)
1375 for (StructureMapping sm : smm)
1377 if (sm.getSequence() == seq)
1384 if (seq.getPrimaryDBRefs().isEmpty())
1386 seqsWithoutSourceDBRef.add(seq);
1390 if (!seqsWithoutSourceDBRef.isEmpty())
1392 int y = seqsWithoutSourceDBRef.size();
1393 setProgressBar(MessageManager.formatMessage(
1394 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1396 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1397 .toArray(new SequenceI[y]);
1398 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1399 dbRefFetcher.fetchDBRefs(true);
1401 setProgressBar("Fetch complete.", progressId); // todo i18n
1404 if (pdbEntriesToView.length > 1)
1407 MessageManager.getString(
1408 "status.fetching_3d_structures_for_selected_entries"),
1410 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
1414 setProgressBar(MessageManager.formatMessage(
1415 "status.fetching_3d_structures_for",
1416 pdbEntriesToView[0].getId()), progressId);
1417 // Can we pass a pre-computeMappinged pdbFile?
1418 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
1420 setProgressBar(null, progressId);
1421 // remember the last viewer we used...
1422 lastTargetedView = theViewer;
1427 * Populates the combo-box used in associating manually fetched structures to
1428 * a unique sequence when more than one sequence selection is made.
1431 protected void populateCmbAssociateSeqOptions(
1432 JComboBox<AssociateSeqOptions> cmb_assSeq,
1433 JLabel lbl_associateSeq)
1435 cmb_assSeq.removeAllItems();
1437 new AssociateSeqOptions("-Select Associated Seq-", null));
1438 lbl_associateSeq.setVisible(false);
1439 if (selectedSequences.length > 1)
1441 for (SequenceI seq : selectedSequences)
1443 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1448 String seqName = selectedSequence.getDisplayId(false);
1449 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1450 lbl_associateSeq.setText(seqName);
1451 lbl_associateSeq.setVisible(true);
1452 cmb_assSeq.setVisible(false);
1456 protected boolean isStructuresDiscovered()
1458 return discoveredStructuresSet != null
1459 && !discoveredStructuresSet.isEmpty();
1462 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1464 // Doing a search for "1" or "1c" is valuable?
1465 // Those work but are enormously slow.
1468 protected void txt_search_ActionPerformed()
1470 String text = txt_search.getText().trim();
1471 if (text.length() >= PDB_ID_MIN)
1478 errorWarning.setLength(0);
1479 isValidPBDEntry = false;
1480 if (text.length() > 0)
1482 // TODO move this pdb id search into the PDB specific
1484 // for moment, it will work fine as is because it is self-contained
1485 String searchTerm = text.toLowerCase(Locale.ROOT);
1486 searchTerm = searchTerm.split(":")[0];
1487 // System.out.println(">>>>> search term : " + searchTerm);
1488 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1489 FTSRestRequest pdbRequest = new FTSRestRequest();
1490 pdbRequest.setAllowEmptySeq(false);
1491 pdbRequest.setResponseSize(1);
1492 pdbRequest.setFieldToSearchBy("(pdb_id:");
1493 pdbRequest.setWantedFields(wantedFields);
1494 pdbRequest.setSearchTerm(searchTerm + ")");
1495 pdbRequest.setAssociatedSequence(selectedSequence);
1496 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1497 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1498 FTSRestResponse resultList;
1501 resultList = pdbRestClient.executeRequest(pdbRequest);
1502 } catch (Exception e)
1504 errorWarning.append(e.getMessage());
1508 validateSelections();
1510 if (resultList.getSearchSummary() != null
1511 && resultList.getSearchSummary().size() > 0)
1513 isValidPBDEntry = true;
1516 validateSelections();
1522 protected void tabRefresh()
1524 if (selectedSequences != null)
1526 lbl_loading.setVisible(true);
1527 Thread refreshThread = new Thread(new Runnable()
1532 fetchStructuresMetaData();
1533 // populateFilterComboBox(true, cachedPDBExists);
1536 ((FilterOption) cmb_filterOption.getSelectedItem())
1538 lbl_loading.setVisible(false);
1541 refreshThread.start();
1545 public class PDBEntryTableModel extends AbstractTableModel
1547 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1550 private List<CachedPDB> pdbEntries;
1552 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1554 this.pdbEntries = new ArrayList<>(pdbEntries);
1558 public String getColumnName(int columnIndex)
1560 return columns[columnIndex];
1564 public int getRowCount()
1566 return pdbEntries.size();
1570 public int getColumnCount()
1572 return columns.length;
1576 public boolean isCellEditable(int row, int column)
1582 public Object getValueAt(int rowIndex, int columnIndex)
1584 Object value = "??";
1585 CachedPDB entry = pdbEntries.get(rowIndex);
1586 switch (columnIndex)
1589 value = entry.getSequence();
1592 value = entry.getQualifiedId();
1595 value = entry.getPdbEntry().getChainCode() == null ? "_"
1596 : entry.getPdbEntry().getChainCode();
1599 value = entry.getPdbEntry().getType();
1602 value = entry.getPdbEntry().getFile();
1609 public Class<?> getColumnClass(int columnIndex)
1611 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1614 public CachedPDB getPDBEntryAt(int row)
1616 return pdbEntries.get(row);
1621 private class CachedPDB
1623 private SequenceI sequence;
1625 private PDBEntry pdbEntry;
1627 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1629 this.sequence = sequence;
1630 this.pdbEntry = pdbEntry;
1633 public String getQualifiedId()
1635 if (pdbEntry.hasProvider())
1637 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1639 return pdbEntry.toString();
1642 public SequenceI getSequence()
1647 public PDBEntry getPdbEntry()
1654 private IProgressIndicator progressBar;
1657 public void setProgressBar(String message, long id)
1659 if (!Platform.isHeadless())
1660 progressBar.setProgressBar(message, id);
1664 public void registerHandler(long id, IProgressIndicatorHandler handler)
1666 progressBar.registerHandler(id, handler);
1670 public boolean operationInProgress()
1672 return progressBar.operationInProgress();
1675 public JalviewStructureDisplayI getOpenedStructureViewer()
1677 return sViewer == null ? null : sViewer.sview;
1681 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1683 data.setDocFieldPrefs(newPrefs);
1689 * @return true when all initialisation threads have finished and dialog is
1692 public boolean isDialogVisible()
1694 return mainFrame != null && data != null && cmb_filterOption != null
1695 && mainFrame.isVisible()
1696 && cmb_filterOption.getSelectedItem() != null;
1701 * @return true if the 3D-Beacons query button will/has been displayed
1703 public boolean isCanQueryTDB()
1708 public boolean isNotQueriedTDBYet()
1710 return notQueriedTDBYet;
1714 * Open a single structure file for a given sequence
1716 public static void openStructureFileForSequence(
1717 StructureSelectionManager ssm, StructureChooser sc,
1718 AlignmentPanel ap, SequenceI seq, boolean prompt,
1719 String sFilename, TFType tft, String paeFilename)
1721 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1722 paeFilename, false, true);
1725 public static void openStructureFileForSequence(
1726 StructureSelectionManager ssm, StructureChooser sc,
1727 AlignmentPanel ap, SequenceI seq, boolean prompt,
1728 String sFilename, TFType tft, String paeFilename,
1729 boolean forceHeadless, boolean showAnnotations)
1731 boolean headless = forceHeadless;
1736 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false);
1739 ssm = ap.getStructureSelectionManager();
1741 PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1742 sFilename, DataSourceType.FILE, seq, prompt, Desktop.instance,
1745 // if headless, "false" in the sc constructor above will avoid GUI behaviour
1746 // in sc.launchStructureViewer()
1747 sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1752 sc.mainFrame.dispose();
1754 if (showAnnotations)
1755 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1758 public static void showReferenceAnnotationsForSequence(AlignFrame af,
1761 AlignViewport av = af.getCurrentView();
1762 AlignmentI al = av.getAlignment();
1764 List<SequenceI> forSequences = new ArrayList<>();
1765 forSequences.add(sequence);
1766 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1767 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1769 final SequenceGroup selectionGroup = av.getSelectionGroup();
1770 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1771 for (AlignmentViewPanel ap : af.getAlignPanels())
1773 // required to readjust the height and position of the PAE
1775 ap.adjustAnnotationHeight();