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.LinkedHashSet;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.concurrent.Callable;
35 import java.util.concurrent.Executors;
37 import javax.swing.JCheckBox;
38 import javax.swing.JComboBox;
39 import javax.swing.JLabel;
40 import javax.swing.JMenuItem;
41 import javax.swing.JPopupMenu;
42 import javax.swing.JTable;
43 import javax.swing.SwingUtilities;
44 import javax.swing.table.AbstractTableModel;
46 import com.stevesoft.pat.Regex;
48 import jalview.api.structures.JalviewStructureDisplayI;
49 import jalview.bin.Cache;
50 import jalview.bin.Console;
51 import jalview.bin.Jalview;
52 import jalview.datamodel.PDBEntry;
53 import jalview.datamodel.SequenceI;
54 import jalview.ext.jmol.JmolParser;
55 import jalview.fts.api.FTSData;
56 import jalview.fts.api.FTSDataColumnI;
57 import jalview.fts.api.FTSRestClientI;
58 import jalview.fts.core.FTSDataColumnPreferences;
59 import jalview.fts.core.FTSRestRequest;
60 import jalview.fts.core.FTSRestResponse;
61 import jalview.fts.service.pdb.PDBFTSRestClient;
62 import jalview.fts.service.threedbeacons.TDB_FTSData;
63 import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
64 import jalview.gui.structurechooser.StructureChooserQuerySource;
65 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
66 import jalview.io.DataSourceType;
67 import jalview.io.JalviewFileChooser;
68 import jalview.io.JalviewFileView;
69 import jalview.jbgui.FilterOption;
70 import jalview.jbgui.GStructureChooser;
71 import jalview.structure.StructureImportSettings.TFType;
72 import jalview.structure.StructureMapping;
73 import jalview.structure.StructureSelectionManager;
74 import jalview.util.MessageManager;
75 import jalview.util.Platform;
76 import jalview.util.StringUtils;
77 import jalview.ws.DBRefFetcher;
78 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
79 import jalview.ws.seqfetcher.DbSourceProxy;
80 import jalview.ws.sifts.SiftsSettings;
83 * Provides the behaviors for the Structure chooser Panel
88 @SuppressWarnings("serial")
89 public class StructureChooser extends GStructureChooser
90 implements IProgressIndicator
92 private static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
95 * warn user if need to fetch more than this many uniprot records at once
97 private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
99 private SequenceI selectedSequence;
101 private SequenceI[] selectedSequences;
103 private IProgressIndicator progressIndicator;
105 private Collection<FTSData> discoveredStructuresSet;
107 private StructureChooserQuerySource data;
110 protected FTSDataColumnPreferences getFTSDocFieldPrefs()
112 return data.getDocFieldPrefs();
115 private String selectedPdbFileName;
117 private TFType localPdbTempfacType;
119 private String localPdbPaeMatrixFileName;
121 private boolean isValidPBDEntry;
123 private boolean cachedPDBExists;
125 private Collection<FTSData> lastDiscoveredStructuresSet;
127 private boolean canQueryTDB = false;
129 private boolean notQueriedTDBYet = true;
131 List<SequenceI> seqsWithoutSourceDBRef = null;
133 private boolean showChooserGUI = true;
135 private static StructureViewer lastTargetedView = null;
137 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
140 this(selectedSeqs, selectedSeq, ap, true);
143 public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
144 AlignmentPanel ap, boolean showGUI)
146 // which FTS engine to use
147 data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
151 this.selectedSequence = selectedSeq;
152 this.selectedSequences = selectedSeqs;
153 this.progressIndicator = (ap == null) ? null : ap.alignFrame;
154 this.showChooserGUI = showGUI;
160 * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
161 * least one structure are discovered.
163 private void populateSeqsWithoutSourceDBRef()
165 seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
166 boolean needCanonical = false;
167 for (SequenceI seq : selectedSequences)
171 int dbRef = ThreeDBStructureChooserQuerySource
172 .checkUniprotRefs(seq.getDBRefs());
177 // need to retrieve canonicals
178 needCanonical = true;
179 seqsWithoutSourceDBRef.add(seq);
183 // could be a sequence with pdb ref
184 if (seq.getAllPDBEntries() == null
185 || seq.getAllPDBEntries().size() == 0)
187 seqsWithoutSourceDBRef.add(seq);
193 // retrieve database refs for protein sequences
194 if (!seqsWithoutSourceDBRef.isEmpty())
199 // triggers display of the 'Query TDB' button
200 notQueriedTDBYet = true;
206 * Initializes parameters used by the Structure Chooser Panel
208 protected void init()
210 if (!Jalview.isHeadlessMode())
212 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
215 chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
216 btn_queryTDB.addActionListener(new ActionListener()
220 public void actionPerformed(ActionEvent e)
222 promptForTDBFetch(false);
226 Executors.defaultThreadFactory().newThread(new Runnable()
231 populateSeqsWithoutSourceDBRef();
232 initialStructureDiscovery();
240 private void initialStructureDiscovery()
242 // check which FTS engine to use
243 data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
245 // ensure a filter option is in force for search
246 populateFilterComboBox(true, cachedPDBExists);
248 // looks for any existing structures already loaded
249 // for the sequences (the cached ones)
250 // then queries the StructureChooserQuerySource to
251 // discover more structures.
253 // Possible optimisation is to only begin querying
254 // the structure chooser if there are no cached structures.
256 long startTime = System.currentTimeMillis();
257 updateProgressIndicator(
258 MessageManager.getString("status.loading_cached_pdb_entries"),
260 loadLocalCachedPDBEntries();
261 updateProgressIndicator(null, startTime);
262 updateProgressIndicator(
263 MessageManager.getString("status.searching_for_pdb_structures"),
265 fetchStructuresMetaData();
266 // revise filter options if no results were found
267 populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
268 discoverStructureViews();
269 updateProgressIndicator(null, startTime);
270 mainFrame.setVisible(showChooserGUI);
275 * raises dialog for Uniprot fetch followed by 3D beacons search
278 * - when true, don't ask, just fetch
280 public void promptForTDBFetch(boolean ignoreGui)
282 final long progressId = System.currentTimeMillis();
284 // final action after prompting and discovering db refs
285 final Runnable strucDiscovery = new Runnable()
290 mainFrame.setEnabled(false);
291 cmb_filterOption.setEnabled(false);
292 progressBar.setProgressBar(
293 MessageManager.getString("status.searching_3d_beacons"),
295 btn_queryTDB.setEnabled(false);
296 // TODO: warn if no accessions discovered
297 populateSeqsWithoutSourceDBRef();
298 // redo initial discovery - this time with 3d beacons
300 previousWantedFields = null;
301 lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
302 cmb_filterOption.setSelectedItem(null);
303 cachedPDBExists = false; // reset to initial
304 initialStructureDiscovery();
305 if (!isStructuresDiscovered())
307 progressBar.setProgressBar(MessageManager.getString(
308 "status.no_structures_discovered_from_3d_beacons"),
310 btn_queryTDB.setToolTipText(MessageManager.getString(
311 "status.no_structures_discovered_from_3d_beacons"));
312 btn_queryTDB.setEnabled(false);
313 pnl_queryTDB.setVisible(false);
317 cmb_filterOption.setSelectedIndex(0); // select 'best'
318 btn_queryTDB.setVisible(false);
319 pnl_queryTDB.setVisible(false);
320 progressBar.setProgressBar(null, progressId);
322 mainFrame.setEnabled(true);
323 cmb_filterOption.setEnabled(true);
327 final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
331 public void finished()
333 // filter has been selected, so we set flag to remove ourselves
334 notQueriedTDBYet = false;
335 // new thread to discover structures - via 3d beacons
336 Executors.defaultThreadFactory().newThread(strucDiscovery).start();
341 // fetch db refs if OK pressed
342 final Callable discoverCanonicalDBrefs = () -> {
343 btn_queryTDB.setEnabled(false);
344 populateSeqsWithoutSourceDBRef();
346 final int y = seqsWithoutSourceDBRef.size();
349 final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
350 .toArray(new SequenceI[y]);
351 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
352 progressBar, new DbSourceProxy[]
353 { new jalview.ws.dbsources.Uniprot() }, null, false);
354 dbRefFetcher.addListener(afterDbRefFetch);
355 // ideally this would also gracefully run with callbacks
357 dbRefFetcher.fetchDBRefs(true);
361 // call finished action directly
362 afterDbRefFetch.finished();
366 final Callable revertview = () -> {
367 if (lastSelected != null)
369 cmb_filterOption.setSelectedItem(lastSelected);
373 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
374 THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
375 Console.debug("Using Uniprot fetch threshold of " + threshold);
376 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
378 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
381 // need cancel and no to result in the discoverPDB action - mocked is
382 // 'cancel' TODO: mock should be OK
384 StructureChooser thisSC = this;
385 JvOptionPane.newOptionDialog(thisSC.getFrame())
386 .setResponseHandler(JvOptionPane.OK_OPTION,
387 discoverCanonicalDBrefs)
388 .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
389 .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
391 MessageManager.formatMessage(
392 "label.fetch_references_for_3dbeacons",
393 seqsWithoutSourceDBRef.size()),
394 MessageManager.getString("label.3dbeacons"),
395 JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
397 { MessageManager.getString("action.ok"),
398 MessageManager.getString("action.cancel") },
399 MessageManager.getString("action.ok"), false);
403 * Builds a drop-down choice list of existing structure viewers to which new
404 * structures may be added. If this list is empty then it, and the 'Add'
405 * button, are hidden.
407 private void discoverStructureViews()
409 if (Desktop.instance != null)
411 targetView.removeAllItems();
412 if (lastTargetedView != null && !lastTargetedView.isVisible())
414 lastTargetedView = null;
416 int linkedViewsAt = 0;
417 for (StructureViewerBase view : Desktop.instance
418 .getStructureViewers(null, null))
420 StructureViewer viewHandler = (lastTargetedView != null
421 && lastTargetedView.sview == view) ? lastTargetedView
422 : StructureViewer.reconfigure(view);
424 if (view.isLinkedWith(ap))
426 targetView.insertItemAt(viewHandler, linkedViewsAt++);
430 targetView.addItem(viewHandler);
435 * show option to Add to viewer if at least 1 viewer found
437 targetView.setVisible(false);
438 if (targetView.getItemCount() > 0)
440 targetView.setVisible(true);
441 if (lastTargetedView != null)
443 targetView.setSelectedItem(lastTargetedView);
447 targetView.setSelectedIndex(0);
450 btn_add.setVisible(targetView.isVisible());
455 * Updates the progress indicator with the specified message
458 * displayed message for the operation
460 * unique handle for this indicator
462 protected void updateProgressIndicator(String message, long id)
464 if (progressIndicator != null)
466 progressIndicator.setProgressBar(message, id);
471 * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
474 void fetchStructuresMetaData()
476 long startTime = System.currentTimeMillis();
477 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
478 .getStructureSummaryFields();
480 discoveredStructuresSet = new LinkedHashSet<>();
481 HashSet<String> errors = new HashSet<>();
483 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
486 for (SequenceI seq : selectedSequences)
489 FTSRestResponse resultList;
492 resultList = data.fetchStructuresMetaData(seq, wantedFields,
493 selectedFilterOpt, !chk_invertFilter.isSelected());
494 // null response means the FTSengine didn't yield a query for this
495 // consider designing a special exception if we really wanted to be
497 if (resultList == null)
501 } catch (Exception e)
504 errors.add(e.getMessage());
507 if (resultList.getSearchSummary() != null
508 && !resultList.getSearchSummary().isEmpty())
510 discoveredStructuresSet.addAll(resultList.getSearchSummary());
514 int noOfStructuresFound = 0;
515 String totalTime = (System.currentTimeMillis() - startTime)
517 if (discoveredStructuresSet != null
518 && !discoveredStructuresSet.isEmpty())
521 .setModel(data.getTableModel(discoveredStructuresSet));
523 noOfStructuresFound = discoveredStructuresSet.size();
524 lastDiscoveredStructuresSet = discoveredStructuresSet;
525 mainFrame.setTitle(MessageManager.formatMessage(
526 "label.structure_chooser_no_of_structures",
527 noOfStructuresFound, totalTime));
531 mainFrame.setTitle(MessageManager
532 .getString("label.structure_chooser_manual_association"));
533 if (errors.size() > 0)
535 StringBuilder errorMsg = new StringBuilder();
536 for (String error : errors)
538 errorMsg.append(error).append("\n");
540 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
541 MessageManager.getString("label.pdb_web-service_error"),
542 JvOptionPane.ERROR_MESSAGE);
547 protected void loadLocalCachedPDBEntries()
549 ArrayList<CachedPDB> entries = new ArrayList<>();
550 for (SequenceI seq : selectedSequences)
552 if (seq.getDatasetSequence() != null
553 && seq.getDatasetSequence().getAllPDBEntries() != null)
555 for (PDBEntry pdbEntry : seq.getDatasetSequence()
558 if (pdbEntry.getFile() != null)
560 entries.add(new CachedPDB(seq, pdbEntry));
565 cachedPDBExists = !entries.isEmpty();
566 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
567 tbl_local_pdb.setModel(tableModelx);
571 * Filters a given list of discovered structures based on supplied argument
573 * @param fieldToFilterBy
574 * the field to filter by
576 void filterResultSet(final String fieldToFilterBy)
578 Thread filterThread = new Thread(new Runnable()
584 long startTime = System.currentTimeMillis();
585 lbl_loading.setVisible(true);
586 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
587 .getStructureSummaryFields();
588 Collection<FTSData> filteredResponse = new HashSet<>();
589 HashSet<String> errors = new HashSet<>();
591 for (SequenceI seq : selectedSequences)
594 FTSRestResponse resultList;
597 resultList = data.selectFirstRankedQuery(seq,
598 discoveredStructuresSet, wantedFields, fieldToFilterBy,
599 !chk_invertFilter.isSelected());
601 } catch (Exception e)
604 errors.add(e.getMessage());
607 if (resultList.getSearchSummary() != null
608 && !resultList.getSearchSummary().isEmpty())
610 filteredResponse.addAll(resultList.getSearchSummary());
614 String totalTime = (System.currentTimeMillis() - startTime)
616 if (!filteredResponse.isEmpty())
618 final int filterResponseCount = filteredResponse.size();
619 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
620 reorderedStructuresSet.addAll(filteredResponse);
621 reorderedStructuresSet.addAll(discoveredStructuresSet);
623 .setModel(data.getTableModel(reorderedStructuresSet));
625 FTSRestResponse.configureTableColumn(getResultTable(),
626 wantedFields, tempUserPrefs);
627 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
628 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
629 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
630 // Update table selection model here
631 getResultTable().addRowSelectionInterval(0,
632 filterResponseCount - 1);
633 mainFrame.setTitle(MessageManager.formatMessage(
634 "label.structure_chooser_filter_time", totalTime));
638 mainFrame.setTitle(MessageManager.formatMessage(
639 "label.structure_chooser_filter_time", totalTime));
640 if (errors.size() > 0)
642 StringBuilder errorMsg = new StringBuilder();
643 for (String error : errors)
645 errorMsg.append(error).append("\n");
647 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
648 MessageManager.getString("label.pdb_web-service_error"),
649 JvOptionPane.ERROR_MESSAGE);
653 lbl_loading.setVisible(false);
655 validateSelections();
658 filterThread.start();
662 * Handles action event for btn_pdbFromFile
665 protected void pdbFromFile_actionPerformed()
667 // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
670 JalviewFileChooser chooser = new JalviewFileChooser(
671 Cache.getProperty("LAST_DIRECTORY"));
672 chooser.setFileView(new JalviewFileView());
673 chooser.setDialogTitle(
674 MessageManager.formatMessage("label.select_pdb_file_for",
675 selectedSequence.getDisplayId(false)));
676 chooser.setToolTipText(MessageManager.formatMessage(
677 "label.load_pdb_file_associate_with_sequence",
678 selectedSequence.getDisplayId(false)));
680 int value = chooser.showOpenDialog(null);
681 if (value == JalviewFileChooser.APPROVE_OPTION)
683 selectedPdbFileName = chooser.getSelectedFile().getPath();
684 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
685 boolean guessTFType = localPdbPaeMatrixFileName == null;
686 localPdbPaeMatrixFileName = guessPAEFilename();
687 guessTFType |= localPdbPaeMatrixFileName != null;
688 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
690 && alphaFold.search(new File(selectedPdbFileName).getName())
691 && !tempFacAsChanged)
693 // localPdbPaeMatrixFileName was null and now isn't and filename could
694 // well be AlphaFold and user hasn't adjusted the tempFacType
695 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
697 validateSelections();
702 * Handles action event for btn_pdbFromFile
705 protected void paeMatrixFile_actionPerformed()
707 File pdbFile = new File(selectedPdbFileName);
708 String setFile = Cache.getProperty("LAST_DIRECTORY");
709 if (localPdbPaeMatrixFileName != null)
711 File paeFile = new File(localPdbPaeMatrixFileName);
712 if (paeFile.exists())
713 setFile = paeFile.getAbsolutePath();
714 else if (paeFile.getParentFile().exists())
715 setFile = paeFile.getParentFile().getAbsolutePath();
719 String guess = guessPAEFilename();
723 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
724 chooser.setFileView(new JalviewFileView());
725 chooser.setDialogTitle(MessageManager.formatMessage(
726 "label.select_pae_matrix_file_for", pdbFile.getName()));
727 chooser.setToolTipText(MessageManager.formatMessage(
728 "label.load_pae_matrix_file_associate_with_structure",
731 int value = chooser.showOpenDialog(null);
732 if (value == JalviewFileChooser.APPROVE_OPTION)
734 localPdbPaeMatrixFileName = chooser.getSelectedFile().getPath();
735 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
737 validateAssociationFromFile();
740 private String guessPAEFilename()
742 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
743 || selectedPdbFileName.toLowerCase(Locale.ROOT)
746 String jsonExt = selectedPdbFileName.substring(0,
747 selectedPdbFileName.length() - 4) + ".json";
748 // AlphaFold naming scheme
749 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
750 "predicted_aligned_error");
751 // nf-core mode naming scheme
752 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
754 if (new File(guessFile1).exists())
758 else if (new File(jsonExt).exists())
762 else if (new File(guessFile2).exists())
771 * Populates the filter combo-box options dynamically depending on discovered
774 protected void populateFilterComboBox(boolean haveData,
775 boolean cachedPDBExist)
777 populateFilterComboBox(haveData, cachedPDBExist, null);
781 * Populates the filter combo-box options dynamically depending on discovered
784 protected void populateFilterComboBox(boolean haveData,
785 boolean cachedPDBExist, FilterOption lastSel)
789 * temporarily suspend the change listener behaviour
791 cmb_filterOption.removeItemListener(this);
793 cmb_filterOption.removeAllItems();
796 List<FilterOption> filters = data
797 .getAvailableFilterOptions(VIEWS_FILTER);
798 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
799 lastDiscoveredStructuresSet);
801 for (FilterOption filter : filters)
803 if (lastSel != null && filter.equals(lastSel))
808 cmb_filterOption.addItem(filter);
812 cmb_filterOption.addItem(
813 new FilterOption(MessageManager.getString("label.enter_pdb_id"),
814 "-", VIEWS_ENTER_ID, false, null));
815 cmb_filterOption.addItem(
816 new FilterOption(MessageManager.getString("label.from_file"),
817 "-", VIEWS_FROM_FILE, false, null));
818 if (canQueryTDB && notQueriedTDBYet)
820 btn_queryTDB.setVisible(true);
821 pnl_queryTDB.setVisible(true);
826 FilterOption cachedOption = new FilterOption(
827 MessageManager.getString("label.cached_structures"), "-",
828 VIEWS_LOCAL_PDB, false, null);
829 cmb_filterOption.addItem(cachedOption);
832 cmb_filterOption.setSelectedItem(cachedOption);
837 cmb_filterOption.setSelectedIndex(selSet);
839 cmb_filterOption.addItemListener(this);
843 * Updates the displayed view based on the selected filter option
845 protected void updateCurrentView()
847 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
850 if (lastSelected == selectedFilterOpt)
852 // don't need to do anything, probably
855 // otherwise, record selection
856 // and update the layout and dialog accordingly
857 lastSelected = selectedFilterOpt;
859 layout_switchableViews.show(pnl_switchableViews,
860 selectedFilterOpt.getView());
861 String filterTitle = mainFrame.getTitle();
862 mainFrame.setTitle(frameTitle);
863 chk_invertFilter.setVisible(false);
865 if (selectedFilterOpt.getView() == VIEWS_FILTER)
867 mainFrame.setTitle(filterTitle);
868 // TDB Query has no invert as yet
869 chk_invertFilter.setVisible(selectedFilterOpt
870 .getQuerySource() instanceof PDBStructureChooserQuerySource);
872 if (data != selectedFilterOpt.getQuerySource()
873 || data.needsRefetch(selectedFilterOpt))
875 data = selectedFilterOpt.getQuerySource();
876 // rebuild the views completely, since prefs will also change
882 filterResultSet(selectedFilterOpt.getValue());
885 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
886 || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
888 mainFrame.setTitle(MessageManager
889 .getString("label.structure_chooser_manual_association"));
890 idInputAssSeqPanel.loadCmbAssSeq();
891 fileChooserAssSeqPanel.loadCmbAssSeq();
893 validateSelections();
897 * Validates user selection and enables the 'Add' and 'New View' buttons if
898 * all parameters are correct (the Add button will only be visible if there is
899 * at least one existing structure viewer open). This basically means at least
900 * one structure selected and no error messages.
902 * The 'Superpose Structures' option is enabled if either more than one
903 * structure is selected, or the 'Add' to existing view option is enabled, and
904 * disabled if the only option is to open a new view of a single structure.
907 protected void validateSelections()
909 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
911 btn_add.setEnabled(false);
912 String currentView = selectedFilterOpt.getView();
913 int selectedCount = 0;
914 if (currentView == VIEWS_FILTER)
916 selectedCount = getResultTable().getSelectedRows().length;
917 if (selectedCount > 0)
919 btn_add.setEnabled(true);
922 else if (currentView == VIEWS_LOCAL_PDB)
924 selectedCount = tbl_local_pdb.getSelectedRows().length;
925 if (selectedCount > 0)
927 btn_add.setEnabled(true);
930 else if (currentView == VIEWS_ENTER_ID)
932 validateAssociationEnterPdb();
934 else if (currentView == VIEWS_FROM_FILE)
936 validateAssociationFromFile();
939 btn_newView.setEnabled(btn_add.isEnabled());
942 * enable 'Superpose' option if more than one structure is selected,
943 * or there are view(s) available to add structure(s) to
946 .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
950 protected boolean showPopupFor(int selectedRow, int x, int y)
952 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
954 String currentView = selectedFilterOpt.getView();
956 if (currentView == VIEWS_FILTER
957 && data instanceof ThreeDBStructureChooserQuerySource)
960 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
961 .getFTSDataFor(getResultTable(), selectedRow,
962 discoveredStructuresSet);
963 String pageUrl = row.getModelViewUrl();
964 JPopupMenu popup = new JPopupMenu("3D Beacons");
965 JMenuItem viewUrl = new JMenuItem("View model web page");
966 viewUrl.addActionListener(new ActionListener()
969 public void actionPerformed(ActionEvent e)
971 Desktop.showUrl(pageUrl);
975 SwingUtilities.invokeLater(new Runnable()
980 popup.show(getResultTable(), x, y);
985 // event not handled by us
990 * Validates inputs from the Manual PDB entry panel
992 protected void validateAssociationEnterPdb()
994 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
995 .getCmb_assSeq().getSelectedItem();
996 lbl_pdbManualFetchStatus.setIcon(errorImage);
997 lbl_pdbManualFetchStatus.setToolTipText("");
998 if (txt_search.getText().length() > 0)
1000 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1001 MessageManager.formatMessage("info.no_pdb_entry_found_for",
1002 txt_search.getText())));
1005 if (errorWarning.length() > 0)
1007 lbl_pdbManualFetchStatus.setIcon(warningImage);
1008 lbl_pdbManualFetchStatus.setToolTipText(
1009 JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1012 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1013 .equalsIgnoreCase("-Select Associated Seq-"))
1015 txt_search.setEnabled(true);
1016 if (isValidPBDEntry)
1018 btn_add.setEnabled(true);
1019 lbl_pdbManualFetchStatus.setToolTipText("");
1020 lbl_pdbManualFetchStatus.setIcon(goodImage);
1025 txt_search.setEnabled(false);
1026 lbl_pdbManualFetchStatus.setIcon(errorImage);
1031 * Validates inputs for the manual PDB file selection options
1033 protected void validateAssociationFromFile()
1035 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1036 .getCmb_assSeq().getSelectedItem();
1037 // lbl_fromFileStatus.setIcon(errorImage);
1038 String pdbFileString = "";
1039 String pdbFileTooltip = "";
1040 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1041 .getName().equalsIgnoreCase("-Select Associated Seq-")))
1043 btn_pdbFromFile.setEnabled(true);
1044 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1046 btn_add.setEnabled(true);
1047 // lbl_fromFileStatus.setIcon(goodImage);
1048 pdbFileString = new File(selectedPdbFileName).getName();
1049 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1050 setPdbOptionsEnabled(true);
1054 pdbFileString = MessageManager.getString("label.none");
1055 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1060 btn_pdbFromFile.setEnabled(false);
1061 // lbl_fromFileStatus.setIcon(errorImage);
1062 pdbFileString = MessageManager.getString("label.none");
1063 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1065 lbl_pdbFile.setText(pdbFileString);
1066 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1069 String paeFileString = "";
1070 String paeFileTooltip = "";
1071 if (localPdbPaeMatrixFileName != null
1072 && localPdbPaeMatrixFileName.length() > 0)
1074 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1075 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1080 paeFileString = MessageManager.getString("label.none");
1081 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1083 lbl_paeFile.setText(paeFileString);
1084 lbl_paeFile.setToolTipText(paeFileTooltip);
1088 protected void cmbAssSeqStateChanged()
1090 validateSelections();
1093 private FilterOption lastSelected = null;
1096 * Handles the state change event for the 'filter' combo-box and 'invert'
1100 protected void stateChanged(ItemEvent e)
1102 if (e.getSource() instanceof JCheckBox)
1104 updateCurrentView();
1108 if (e.getStateChange() == ItemEvent.SELECTED)
1110 updateCurrentView();
1117 * select structures for viewing by their PDB IDs
1120 * @return true if structures were found and marked as selected
1122 public boolean selectStructure(String... pdbids)
1124 boolean found = false;
1126 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1127 .getSelectedItem());
1128 String currentView = selectedFilterOpt.getView();
1129 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1130 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1132 if (restable == null)
1134 // can't select (enter PDB ID, or load file - need to also select which
1135 // sequence to associate with)
1139 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1140 for (int r = 0; r < restable.getRowCount(); r++)
1142 for (int p = 0; p < pdbids.length; p++)
1144 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1145 .equalsIgnoreCase(pdbids[p]))
1147 restable.setRowSelectionInterval(r, r);
1156 * Handles the 'New View' action
1159 protected void newView_ActionPerformed()
1161 targetView.setSelectedItem(null);
1162 showStructures(false);
1166 * Handles the 'Add to existing viewer' action
1169 protected void add_ActionPerformed()
1171 showStructures(false);
1175 * structure viewer opened by this dialog, or null
1177 private StructureViewer sViewer = null;
1179 public void showStructures(boolean waitUntilFinished)
1182 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1184 final int preferredHeight = pnl_filter.getHeight();
1186 Runnable viewStruc = new Runnable()
1191 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1192 .getSelectedItem());
1193 String currentView = selectedFilterOpt.getView();
1194 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1197 if (currentView == VIEWS_FILTER)
1199 int[] selectedRows = restable.getSelectedRows();
1200 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1201 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1202 pdbEntriesToView = data.collectSelectedRows(restable,
1203 selectedRows, selectedSeqsToView);
1205 SequenceI[] selectedSeqs = selectedSeqsToView
1206 .toArray(new SequenceI[selectedSeqsToView.size()]);
1207 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1210 else if (currentView == VIEWS_LOCAL_PDB)
1212 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1213 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1215 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1217 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1219 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1220 for (int row : selectedRows)
1222 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1223 .getModel()).getPDBEntryAt(row).getPdbEntry();
1225 pdbEntriesToView[count++] = pdbEntry;
1226 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1227 .getValueAt(row, refSeqColIndex);
1228 selectedSeqsToView.add(selectedSeq);
1230 SequenceI[] selectedSeqs = selectedSeqsToView
1231 .toArray(new SequenceI[selectedSeqsToView.size()]);
1232 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1235 else if (currentView == VIEWS_ENTER_ID)
1237 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1238 .getCmb_assSeq().getSelectedItem()).getSequence();
1239 if (userSelectedSeq != null)
1241 selectedSequence = userSelectedSeq;
1243 String pdbIdStr = txt_search.getText();
1244 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1245 if (pdbEntry == null)
1247 pdbEntry = new PDBEntry();
1248 if (pdbIdStr.split(":").length > 1)
1250 pdbEntry.setId(pdbIdStr.split(":")[0]);
1251 pdbEntry.setChainCode(
1252 pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1256 pdbEntry.setId(pdbIdStr);
1258 pdbEntry.setType(PDBEntry.Type.PDB);
1259 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1262 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1263 sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap,
1265 { selectedSequence });
1267 else if (currentView == VIEWS_FROM_FILE)
1269 TFType tft = (TFType) StructureChooser.this.combo_tempFacAs
1271 String paeFilename = StructureChooser.this.localPdbPaeMatrixFileName;
1272 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1273 .getCmb_assSeq().getSelectedItem();
1274 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1275 if (userSelectedSeq != null)
1276 selectedSequence = userSelectedSeq;
1277 String pdbFilename = selectedPdbFileName;
1279 PDBEntry fileEntry = new AssociatePdbFileWithSeq()
1280 .associatePdbWithSeq(pdbFilename, DataSourceType.FILE,
1281 selectedSequence, true, Desktop.instance, tft,
1285 SequenceI[] seqArray = new SequenceI[] { selectedSequence };
1287 StructureFile sf = ssm.computeMapping(true, seqArray, null,
1288 selectedPdbFileName, DataSourceType.FILE, null, tft,
1290 StructureMapping[] sm = ssm.getMapping(fileEntry.getFile());
1291 // DO SOMETHING WITH
1292 File paeFile = paeFilename == null ? null : new File(paeFilename);
1293 if (paeFilename != null && paeFile.exists())
1295 AlignmentI al = StructureChooser.this.ap.getAlignment();
1298 EBIAlfaFold.importPaeJSONAsContactMatrixToSequence(al,
1299 paeFile, selectedSequence);
1300 } catch (IOException | ParseException e)
1302 // TODO Auto-generated catch block
1303 e.printStackTrace();
1307 sViewer = launchStructureViewer(ssm, new PDBEntry[] { fileEntry },
1309 { selectedSequence });
1311 SwingUtilities.invokeLater(new Runnable()
1316 closeAction(preferredHeight);
1317 mainFrame.dispose();
1322 Thread runner = new Thread(viewStruc);
1324 if (waitUntilFinished)
1326 while (sViewer == null ? runner.isAlive()
1327 : (sViewer.sview == null ? true
1328 : !sViewer.sview.hasMapping()))
1333 } catch (InterruptedException ie)
1342 * Answers a structure viewer (new or existing) configured to superimpose
1343 * added structures or not according to the user's choice
1348 StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1350 Object sv = targetView.getSelectedItem();
1352 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1356 * Adds PDB structures to a new or existing structure viewer
1359 * @param pdbEntriesToView
1364 private StructureViewer launchStructureViewer(
1365 StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1366 final AlignmentPanel alignPanel, SequenceI[] sequences)
1368 long progressId = sequences.hashCode();
1369 setProgressBar(MessageManager
1370 .getString("status.launching_3d_structure_viewer"), progressId);
1371 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1372 boolean superimpose = chk_superpose.isSelected();
1373 theViewer.setSuperpose(superimpose);
1376 * remember user's choice of superimpose or not
1378 Cache.setProperty(AUTOSUPERIMPOSE,
1379 Boolean.valueOf(superimpose).toString());
1381 setProgressBar(null, progressId);
1382 if (SiftsSettings.isMapWithSifts())
1384 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1386 // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1387 // real PDB ID. For moment, we can also safely do this if there is already
1388 // a known mapping between the PDBEntry and the sequence.
1389 for (SequenceI seq : sequences)
1391 PDBEntry pdbe = pdbEntriesToView[p++];
1393 "##### pdbe=" + pdbe == null ? null : pdbe.toString());
1394 Console.debug("##### pdbe.getFile()=" + pdbe == null ? null
1396 if (pdbe != null && pdbe.getFile() != null)
1398 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1399 if (smm != null && smm.length > 0)
1401 for (StructureMapping sm : smm)
1403 if (sm.getSequence() == seq)
1410 if (seq.getPrimaryDBRefs().isEmpty())
1412 seqsWithoutSourceDBRef.add(seq);
1416 if (!seqsWithoutSourceDBRef.isEmpty())
1418 int y = seqsWithoutSourceDBRef.size();
1419 setProgressBar(MessageManager.formatMessage(
1420 "status.fetching_dbrefs_for_sequences_without_valid_refs",
1422 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1423 .toArray(new SequenceI[y]);
1424 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1425 dbRefFetcher.fetchDBRefs(true);
1427 setProgressBar("Fetch complete.", progressId); // todo i18n
1430 if (pdbEntriesToView.length > 1)
1433 MessageManager.getString(
1434 "status.fetching_3d_structures_for_selected_entries"),
1436 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
1440 setProgressBar(MessageManager.formatMessage(
1441 "status.fetching_3d_structures_for",
1442 pdbEntriesToView[0].getId()), progressId);
1443 // Can we pass a pre-computeMappinged pdbFile?
1444 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
1446 setProgressBar(null, progressId);
1447 // remember the last viewer we used...
1448 lastTargetedView = theViewer;
1453 * Populates the combo-box used in associating manually fetched structures to
1454 * a unique sequence when more than one sequence selection is made.
1457 protected void populateCmbAssociateSeqOptions(
1458 JComboBox<AssociateSeqOptions> cmb_assSeq,
1459 JLabel lbl_associateSeq)
1461 cmb_assSeq.removeAllItems();
1463 new AssociateSeqOptions("-Select Associated Seq-", null));
1464 lbl_associateSeq.setVisible(false);
1465 if (selectedSequences.length > 1)
1467 for (SequenceI seq : selectedSequences)
1469 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1474 String seqName = selectedSequence.getDisplayId(false);
1475 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1476 lbl_associateSeq.setText(seqName);
1477 lbl_associateSeq.setVisible(true);
1478 cmb_assSeq.setVisible(false);
1482 protected boolean isStructuresDiscovered()
1484 return discoveredStructuresSet != null
1485 && !discoveredStructuresSet.isEmpty();
1488 protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1490 // Doing a search for "1" or "1c" is valuable?
1491 // Those work but are enormously slow.
1494 protected void txt_search_ActionPerformed()
1496 String text = txt_search.getText().trim();
1497 if (text.length() >= PDB_ID_MIN)
1504 errorWarning.setLength(0);
1505 isValidPBDEntry = false;
1506 if (text.length() > 0)
1508 // TODO move this pdb id search into the PDB specific
1510 // for moment, it will work fine as is because it is self-contained
1511 String searchTerm = text.toLowerCase(Locale.ROOT);
1512 searchTerm = searchTerm.split(":")[0];
1513 // System.out.println(">>>>> search term : " + searchTerm);
1514 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1515 FTSRestRequest pdbRequest = new FTSRestRequest();
1516 pdbRequest.setAllowEmptySeq(false);
1517 pdbRequest.setResponseSize(1);
1518 pdbRequest.setFieldToSearchBy("(pdb_id:");
1519 pdbRequest.setWantedFields(wantedFields);
1520 pdbRequest.setSearchTerm(searchTerm + ")");
1521 pdbRequest.setAssociatedSequence(selectedSequence);
1522 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1523 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1524 FTSRestResponse resultList;
1527 resultList = pdbRestClient.executeRequest(pdbRequest);
1528 } catch (Exception e)
1530 errorWarning.append(e.getMessage());
1534 validateSelections();
1536 if (resultList.getSearchSummary() != null
1537 && resultList.getSearchSummary().size() > 0)
1539 isValidPBDEntry = true;
1542 validateSelections();
1548 protected void tabRefresh()
1550 if (selectedSequences != null)
1552 lbl_loading.setVisible(true);
1553 Thread refreshThread = new Thread(new Runnable()
1558 fetchStructuresMetaData();
1559 // populateFilterComboBox(true, cachedPDBExists);
1562 ((FilterOption) cmb_filterOption.getSelectedItem())
1564 lbl_loading.setVisible(false);
1567 refreshThread.start();
1571 public class PDBEntryTableModel extends AbstractTableModel
1573 String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1576 private List<CachedPDB> pdbEntries;
1578 public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1580 this.pdbEntries = new ArrayList<>(pdbEntries);
1584 public String getColumnName(int columnIndex)
1586 return columns[columnIndex];
1590 public int getRowCount()
1592 return pdbEntries.size();
1596 public int getColumnCount()
1598 return columns.length;
1602 public boolean isCellEditable(int row, int column)
1608 public Object getValueAt(int rowIndex, int columnIndex)
1610 Object value = "??";
1611 CachedPDB entry = pdbEntries.get(rowIndex);
1612 switch (columnIndex)
1615 value = entry.getSequence();
1618 value = entry.getQualifiedId();
1621 value = entry.getPdbEntry().getChainCode() == null ? "_"
1622 : entry.getPdbEntry().getChainCode();
1625 value = entry.getPdbEntry().getType();
1628 value = entry.getPdbEntry().getFile();
1635 public Class<?> getColumnClass(int columnIndex)
1637 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1640 public CachedPDB getPDBEntryAt(int row)
1642 return pdbEntries.get(row);
1647 private class CachedPDB
1649 private SequenceI sequence;
1651 private PDBEntry pdbEntry;
1653 public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1655 this.sequence = sequence;
1656 this.pdbEntry = pdbEntry;
1659 public String getQualifiedId()
1661 if (pdbEntry.hasProvider())
1663 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1665 return pdbEntry.toString();
1668 public SequenceI getSequence()
1673 public PDBEntry getPdbEntry()
1680 private IProgressIndicator progressBar;
1683 public void setProgressBar(String message, long id)
1685 if (!Platform.isHeadless())
1686 progressBar.setProgressBar(message, id);
1690 public void registerHandler(long id, IProgressIndicatorHandler handler)
1692 progressBar.registerHandler(id, handler);
1696 public boolean operationInProgress()
1698 return progressBar.operationInProgress();
1701 public JalviewStructureDisplayI getOpenedStructureViewer()
1703 return sViewer == null ? null : sViewer.sview;
1707 protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1709 data.setDocFieldPrefs(newPrefs);
1715 * @return true when all initialisation threads have finished and dialog is
1718 public boolean isDialogVisible()
1720 return mainFrame != null && data != null && cmb_filterOption != null
1721 && mainFrame.isVisible()
1722 && cmb_filterOption.getSelectedItem() != null;
1727 * @return true if the 3D-Beacons query button will/has been displayed
1729 public boolean isCanQueryTDB()
1734 public boolean isNotQueriedTDBYet()
1736 return notQueriedTDBYet;
1740 * Open a single structure file for a given sequence
1742 public static void openStructureFileForSequence(AlignmentPanel ap,
1743 SequenceI seq, File sFile)
1745 // Open the chooser headlessly. Not sure this is actually needed ?
1746 StructureChooser sc = new StructureChooser(new SequenceI[] { seq }, seq,
1748 StructureSelectionManager ssm = ap.getStructureSelectionManager();
1749 PDBEntry fileEntry = null;
1752 fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
1753 sFile.getAbsolutePath(), DataSourceType.FILE, seq, true,
1755 } catch (Exception e)
1757 Console.error("Could not open structure file '"
1758 + sFile.getAbsolutePath() + "'");
1762 StructureViewer sViewer = sc.launchStructureViewer(ssm,
1764 { fileEntry }, ap, new SequenceI[] { seq });
1766 sc.mainFrame.dispose();