Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package jalview.gui

File StructureChooser.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
49% of files have more coverage

Code metrics

234
637
77
3
2,017
1,549
233
0.37
8.27
25.67
3.03

Classes

Class Line # Actions
StructureChooser 100 604 213
0.3957636739.6%
StructureChooser.PDBEntryTableModel 1638 26 15
0.2105263221.1%
StructureChooser.CachedPDB 1714 7 5
0.00%
 

Contributing tests

This file is covered by 34 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21   
22    package jalview.gui;
23   
24    import java.awt.event.ActionEvent;
25    import java.awt.event.ActionListener;
26    import java.awt.event.ItemEvent;
27    import java.io.File;
28    import java.io.IOException;
29    import java.util.ArrayList;
30    import java.util.Collection;
31    import java.util.HashSet;
32    import java.util.LinkedHashMap;
33    import java.util.LinkedHashSet;
34    import java.util.List;
35    import java.util.Locale;
36    import java.util.Map;
37    import java.util.concurrent.Executors;
38   
39    import javax.swing.JCheckBox;
40    import javax.swing.JComboBox;
41    import javax.swing.JLabel;
42    import javax.swing.JMenu;
43    import javax.swing.JMenuItem;
44    import javax.swing.JPopupMenu;
45    import javax.swing.JProgressBar;
46    import javax.swing.JTable;
47    import javax.swing.SwingUtilities;
48    import javax.swing.table.AbstractTableModel;
49   
50    import com.stevesoft.pat.Regex;
51   
52    import jalview.analysis.AlignmentUtils;
53    import jalview.api.AlignmentViewPanel;
54    import jalview.api.structures.JalviewStructureDisplayI;
55    import jalview.bin.Cache;
56    import jalview.bin.Console;
57    import jalview.bin.Jalview;
58    import jalview.datamodel.AlignmentAnnotation;
59    import jalview.datamodel.AlignmentI;
60    import jalview.datamodel.PDBEntry;
61    import jalview.datamodel.SequenceGroup;
62    import jalview.datamodel.SequenceI;
63    import jalview.ext.jmol.JmolParser;
64    import jalview.fts.api.FTSData;
65    import jalview.fts.api.FTSDataColumnI;
66    import jalview.fts.api.FTSRestClientI;
67    import jalview.fts.core.FTSDataColumnPreferences;
68    import jalview.fts.core.FTSRestRequest;
69    import jalview.fts.core.FTSRestResponse;
70    import jalview.fts.service.pdb.PDBFTSRestClient;
71    import jalview.fts.service.threedbeacons.TDB_FTSData;
72    import jalview.gui.StructureViewer.ViewerType;
73    import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
74    import jalview.gui.structurechooser.StructureChooserQuerySource;
75    import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
76    import jalview.io.DataSourceType;
77    import jalview.io.JalviewFileChooser;
78    import jalview.io.JalviewFileView;
79    import jalview.jbgui.FilterOption;
80    import jalview.jbgui.GStructureChooser;
81    import jalview.structure.StructureImportSettings.TFType;
82    import jalview.structure.StructureMapping;
83    import jalview.structure.StructureSelectionManager;
84    import jalview.util.MessageManager;
85    import jalview.util.Platform;
86    import jalview.util.StringUtils;
87    import jalview.ws.DBRefFetcher;
88    import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
89    import jalview.ws.datamodel.alphafold.PAEContactMatrix;
90    import jalview.ws.seqfetcher.DbSourceProxy;
91    import jalview.ws.sifts.SiftsSettings;
92   
93    /**
94    * Provides the behaviors for the Structure chooser Panel
95    *
96    * @author tcnofoegbu
97    *
98    */
99    @SuppressWarnings("serial")
 
100    public class StructureChooser extends GStructureChooser
101    implements IProgressIndicator
102    {
103    public static final String AUTOSUPERIMPOSE = "AUTOSUPERIMPOSE";
104   
105    /**
106    * warn user if need to fetch more than this many uniprot records at once
107    */
108    private static final int THRESHOLD_WARN_UNIPROT_FETCH_NEEDED = 20;
109    private SequenceI selectedSequence;
110   
111    private SequenceI[] selectedSequences;
112   
113    private IProgressIndicator progressIndicator;
114   
115    private Collection<FTSData> discoveredStructuresSet;
116   
117    private StructureChooserQuerySource data;
118   
 
119  55 toggle @Override
120    protected FTSDataColumnPreferences getFTSDocFieldPrefs()
121    {
122  55 return data.getDocFieldPrefs();
123    }
124   
125    private String selectedPdbFileName;
126   
127    private String localPdbPaeMatrixFileName;
128   
129    private boolean isValidPBDEntry;
130   
131    private boolean cachedPDBExists;
132   
133    private Collection<FTSData> lastDiscoveredStructuresSet;
134   
135    private boolean canQueryTDB = false;
136   
137    private boolean notQueriedTDBYet = true;
138   
139    List<SequenceI> seqsWithoutSourceDBRef = null;
140   
141    private boolean showChooserGUI = true;
142   
143    /**
144    * when true, queries to external services are supressed (no SIFTs, no PDBe,
145    * no 3D-Beacons, etc)
146    */
147    private boolean dontQueryServices = false;
148   
149    protected static StructureViewer lastTargetedView = null;
150   
 
151  3 toggle public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
152    AlignmentPanel ap)
153    {
154  3 this(selectedSeqs, selectedSeq, ap, true);
155    }
156   
 
157  3 toggle public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
158    AlignmentPanel ap, boolean showGUI)
159    {
160  3 this(selectedSeqs, selectedSeq, ap, showGUI, false);
161    }
162   
 
163  55 toggle public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
164    AlignmentPanel ap, boolean showGUI, boolean dontQueryServices)
165    {
166   
167    // which FTS engine to use
168  55 data = StructureChooserQuerySource.getQuerySourceFor(selectedSeqs);
169  55 initDialog();
170   
171  55 this.ap = ap;
172  55 this.selectedSequence = selectedSeq;
173  55 this.selectedSequences = selectedSeqs;
174  55 this.progressIndicator = (ap == null) ? null : ap.alignFrame;
175  55 this.showChooserGUI = showGUI;
176  55 this.dontQueryServices = dontQueryServices;
177  55 init();
178   
179    }
180   
181    /**
182    * sets canQueryTDB if protein sequences without a canonical uniprot ref or at
183    * least one structure are discovered.
184    */
 
185  3 toggle private void populateSeqsWithoutSourceDBRef()
186    {
187  3 seqsWithoutSourceDBRef = new ArrayList<SequenceI>();
188  3 boolean needCanonical = false;
189  3 for (SequenceI seq : selectedSequences)
190    {
191  3 if (seq.isProtein())
192    {
193  3 int dbRef = ThreeDBStructureChooserQuerySource
194    .checkUniprotRefs(seq.getDBRefs());
195  3 if (dbRef < 0)
196    {
197  2 if (dbRef == -1)
198    {
199    // need to retrieve canonicals
200  1 needCanonical = true;
201  1 seqsWithoutSourceDBRef.add(seq);
202    }
203    else
204    {
205    // could be a sequence with pdb ref
206  1 if (seq.getAllPDBEntries() == null
207    || seq.getAllPDBEntries().size() == 0)
208    {
209  0 seqsWithoutSourceDBRef.add(seq);
210    }
211    }
212    }
213    }
214    }
215    // retrieve database refs for protein sequences
216  3 if (!seqsWithoutSourceDBRef.isEmpty())
217    {
218  1 canQueryTDB = true;
219  1 if (needCanonical)
220    {
221    // triggers display of the 'Query TDB' button
222  1 notQueriedTDBYet = true;
223    }
224    }
225    };
226   
227    /**
228    * Initializes parameters used by the Structure Chooser Panel
229    */
 
230  55 toggle protected void init()
231    {
232  55 if (!Jalview.isHeadlessMode())
233    {
234  53 progressBar = new ProgressBar(this.statusPanel, this.statusBar);
235    }
236   
237  55 chk_superpose.setSelected(Cache.getDefault(AUTOSUPERIMPOSE, true));
238  55 btn_queryTDB.addActionListener(new ActionListener()
239    {
240   
 
241  0 toggle @Override
242    public void actionPerformed(ActionEvent e)
243    {
244  0 promptForTDBFetch(false);
245    }
246    });
247   
248  55 if (!dontQueryServices)
249    {
250  3 Executors.defaultThreadFactory().newThread(new Runnable()
251    {
 
252  3 toggle @Override
253    public void run()
254    {
255  3 populateSeqsWithoutSourceDBRef();
256  3 initialStructureDiscovery();
257    }
258   
259    }).start();
260    }
261    else
262    {
263  52 Console.debug(
264    "Structure chooser not querying services to discover metadata.");
265    }
266    }
267   
268    // called by init
 
269  3 toggle private void initialStructureDiscovery()
270    {
271    // check which FTS engine to use
272  3 data = StructureChooserQuerySource.getQuerySourceFor(selectedSequences);
273   
274    // ensure a filter option is in force for search
275  3 populateFilterComboBox(true, cachedPDBExists);
276   
277    // looks for any existing structures already loaded
278    // for the sequences (the cached ones)
279    // then queries the StructureChooserQuerySource to
280    // discover more structures.
281    //
282    // Possible optimisation is to only begin querying
283    // the structure chooser if there are no cached structures.
284   
285  3 long startTime = System.currentTimeMillis();
286  3 updateProgressIndicator(
287    MessageManager.getString("status.loading_cached_pdb_entries"),
288    startTime);
289  3 loadLocalCachedPDBEntries();
290  3 updateProgressIndicator(null, startTime);
291  3 updateProgressIndicator(
292    MessageManager.getString("status.searching_for_pdb_structures"),
293    startTime);
294  3 fetchStructuresMetaData();
295    // revise filter options if no results were found
296  3 populateFilterComboBox(isStructuresDiscovered(), cachedPDBExists);
297  3 discoverStructureViews();
298  2 updateProgressIndicator(null, startTime);
299  2 mainFrame.setVisible(showChooserGUI);
300  2 updateCurrentView();
301    }
302   
303    /**
304    * raises dialog for Uniprot fetch followed by 3D beacons search
305    *
306    * @param ignoreGui
307    * - when true, don't ask, just fetch
308    */
 
309  0 toggle public void promptForTDBFetch(boolean ignoreGui)
310    {
311  0 final long progressId = System.currentTimeMillis();
312   
313    // final action after prompting and discovering db refs
314  0 final Runnable strucDiscovery = new Runnable()
315    {
 
316  0 toggle @Override
317    public void run()
318    {
319  0 mainFrame.setEnabled(false);
320  0 cmb_filterOption.setEnabled(false);
321  0 progressBar.setProgressBar(
322    MessageManager.getString("status.searching_3d_beacons"),
323    progressId);
324  0 btn_queryTDB.setEnabled(false);
325    // TODO: warn if no accessions discovered
326  0 populateSeqsWithoutSourceDBRef();
327    // redo initial discovery - this time with 3d beacons
328    // Executors.
329  0 previousWantedFields = null;
330  0 lastSelected = (FilterOption) cmb_filterOption.getSelectedItem();
331  0 cmb_filterOption.setSelectedItem(null);
332  0 cachedPDBExists=false; // reset to initial
333  0 initialStructureDiscovery();
334  0 if (!isStructuresDiscovered())
335    {
336  0 progressBar.setProgressBar(MessageManager.getString(
337    "status.no_structures_discovered_from_3d_beacons"),
338    progressId);
339  0 btn_queryTDB.setToolTipText(MessageManager.getString(
340    "status.no_structures_discovered_from_3d_beacons"));
341  0 btn_queryTDB.setEnabled(false);
342  0 pnl_queryTDB.setVisible(false);
343    }
344    else
345    {
346  0 cmb_filterOption.setSelectedIndex(0); // select 'best'
347  0 btn_queryTDB.setVisible(false);
348  0 pnl_queryTDB.setVisible(false);
349  0 progressBar.setProgressBar(null, progressId);
350    }
351  0 mainFrame.setEnabled(true);
352  0 cmb_filterOption.setEnabled(true);
353    }
354    };
355   
356  0 final FetchFinishedListenerI afterDbRefFetch = new FetchFinishedListenerI()
357    {
358   
 
359  0 toggle @Override
360    public void finished()
361    {
362    // filter has been selected, so we set flag to remove ourselves
363  0 notQueriedTDBYet = false;
364    // new thread to discover structures - via 3d beacons
365  0 Executors.defaultThreadFactory().newThread(strucDiscovery).start();
366   
367    }
368    };
369   
370    // fetch db refs if OK pressed
371  0 final Runnable discoverCanonicalDBrefs = () -> {
372  0 btn_queryTDB.setEnabled(false);
373  0 populateSeqsWithoutSourceDBRef();
374   
375  0 final int y = seqsWithoutSourceDBRef.size();
376  0 if (y > 0)
377    {
378  0 final SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
379    .toArray(new SequenceI[y]);
380  0 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef,
381    progressBar, new DbSourceProxy[]
382    { new jalview.ws.dbsources.Uniprot() }, null, false);
383  0 dbRefFetcher.addListener(afterDbRefFetch);
384    // ideally this would also gracefully run with callbacks
385  0 dbRefFetcher.fetchDBRefs(true);
386    }
387    else
388    {
389    // call finished action directly
390  0 afterDbRefFetch.finished();
391    }
392    };
393  0 final Runnable revertview = () -> {
394  0 if (lastSelected != null)
395    {
396  0 cmb_filterOption.setSelectedItem(lastSelected);
397    }
398    };
399  0 int threshold = Cache.getDefault("UNIPROT_AUTOFETCH_THRESHOLD",
400    THRESHOLD_WARN_UNIPROT_FETCH_NEEDED);
401  0 Console.debug("Using Uniprot fetch threshold of " + threshold);
402  0 if (ignoreGui || seqsWithoutSourceDBRef.size() < threshold)
403    {
404  0 Executors.newSingleThreadExecutor().submit(discoverCanonicalDBrefs);
405  0 return;
406    }
407    // need cancel and no to result in the discoverPDB action - mocked is
408    // 'cancel' TODO: mock should be OK
409  0 StructureChooser thisSC = this;
410  0 JvOptionPane.newOptionDialog(thisSC.getFrame())
411    .setResponseHandler(JvOptionPane.OK_OPTION,
412    discoverCanonicalDBrefs)
413    .setResponseHandler(JvOptionPane.CANCEL_OPTION, revertview)
414    .setResponseHandler(JvOptionPane.NO_OPTION, revertview)
415    .showDialog(
416    MessageManager.formatMessage(
417    "label.fetch_references_for_3dbeacons",
418    seqsWithoutSourceDBRef.size()),
419    MessageManager
420    .getString("label.3dbeacons"),
421    JvOptionPane.YES_NO_OPTION, JvOptionPane.PLAIN_MESSAGE,
422    null, new Object[]
423    { MessageManager.getString("action.ok"),
424    MessageManager.getString("action.cancel") },
425    MessageManager.getString("action.ok"), false);
426    }
427   
428    /**
429    * Builds a drop-down choice list of existing structure viewers to which new
430    * structures may be added. If this list is empty then it, and the 'Add'
431    * button, are hidden.
432    */
 
433  3 toggle private void discoverStructureViews()
434    {
435  3 if (Desktop.getInstance() != null)
436    {
437  3 targetView.removeAllItems();
438  3 if (lastTargetedView != null && !lastTargetedView.isVisible())
439    {
440  0 lastTargetedView = null;
441    }
442  3 int linkedViewsAt = 0;
443  3 for (StructureViewerBase view : Desktop.getInstance()
444    .getStructureViewers(null, null))
445    {
446  1 StructureViewer viewHandler = (lastTargetedView != null
447    && lastTargetedView.sview == view) ? lastTargetedView
448    : StructureViewer.reconfigure(view);
449   
450  0 if (view.isLinkedWith(ap))
451    {
452  0 targetView.insertItemAt(viewHandler, linkedViewsAt++);
453    }
454    else
455    {
456  0 targetView.addItem(viewHandler);
457    }
458    }
459   
460    /*
461    * show option to Add to viewer if at least 1 viewer found
462    */
463  2 targetView.setVisible(false);
464  2 if (targetView.getItemCount() > 0)
465    {
466  0 targetView.setVisible(true);
467  0 if (lastTargetedView != null)
468    {
469  0 targetView.setSelectedItem(lastTargetedView);
470    }
471    else
472    {
473  0 targetView.setSelectedIndex(0);
474    }
475    }
476  2 btn_add.setVisible(targetView.isVisible());
477    }
478    }
479   
480    /**
481    * Updates the progress indicator with the specified message
482    *
483    * @param message
484    * displayed message for the operation
485    * @param id
486    * unique handle for this indicator
487    */
 
488  11 toggle protected void updateProgressIndicator(String message, long id)
489    {
490  11 if (progressIndicator != null)
491    {
492  0 progressIndicator.setProgressBar(message, id);
493    }
494    }
495   
496    /**
497    * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
498    * selection group
499    */
 
500  4 toggle void fetchStructuresMetaData()
501    {
502  4 long startTime = System.currentTimeMillis();
503  4 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
504    .getStructureSummaryFields();
505   
506  4 discoveredStructuresSet = new LinkedHashSet<>();
507  4 HashSet<String> errors = new HashSet<>();
508   
509  4 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
510    .getSelectedItem());
511   
512  4 for (SequenceI seq : selectedSequences)
513    {
514   
515  4 FTSRestResponse resultList;
516  4 try
517    {
518  4 resultList = data.fetchStructuresMetaData(seq, wantedFields,
519    selectedFilterOpt, !chk_invertFilter.isSelected());
520    // null response means the FTSengine didn't yield a query for this
521    // consider designing a special exception if we really wanted to be
522    // OOCrazy
523  2 if (resultList == null)
524    {
525  0 continue;
526    }
527    } catch (Exception e)
528    {
529  2 Console.printStackTrace(e);
530  2 errors.add(e.getMessage());
531  2 continue;
532    }
533  2 if (resultList.getSearchSummary() != null
534    && !resultList.getSearchSummary().isEmpty())
535    {
536  2 discoveredStructuresSet.addAll(resultList.getSearchSummary());
537    }
538    }
539   
540  4 int noOfStructuresFound = 0;
541  4 String totalTime = (System.currentTimeMillis() - startTime)
542    + " milli secs";
543  4 if (discoveredStructuresSet != null
544    && !discoveredStructuresSet.isEmpty())
545    {
546  2 getResultTable()
547    .setModel(data.getTableModel(discoveredStructuresSet));
548   
549  2 noOfStructuresFound = discoveredStructuresSet.size();
550  2 lastDiscoveredStructuresSet = discoveredStructuresSet;
551  2 mainFrame.setTitle(MessageManager.formatMessage(
552    "label.structure_chooser_no_of_structures",
553    noOfStructuresFound, totalTime));
554    }
555    else
556    {
557  2 mainFrame.setTitle(MessageManager
558    .getString("label.structure_chooser_manual_association"));
559  2 if (errors.size() > 0)
560    {
561  2 StringBuilder errorMsg = new StringBuilder();
562  2 for (String error : errors)
563    {
564  2 errorMsg.append(error).append("\n");
565    }
566  2 if (!Jalview.isHeadlessMode())
567    {
568  2 JvOptionPane.showMessageDialog(this, errorMsg.toString(),
569    MessageManager.getString("label.pdb_web-service_error"),
570    JvOptionPane.ERROR_MESSAGE);
571    }
572    else
573    {
574  0 Console.error(
575    MessageManager.getString("label.pdb_web-service_error"));
576  0 Console.debug(errorMsg.toString());
577    }
578    }
579    }
580    }
581   
 
582  3 toggle protected void loadLocalCachedPDBEntries()
583    {
584  3 ArrayList<CachedPDB> entries = new ArrayList<>();
585  3 for (SequenceI seq : selectedSequences)
586    {
587  3 if (seq.getDatasetSequence() != null
588    && seq.getDatasetSequence().getAllPDBEntries() != null)
589    {
590  3 for (PDBEntry pdbEntry : seq.getDatasetSequence()
591    .getAllPDBEntries())
592    {
593  0 if (pdbEntry.getFile() != null)
594    {
595  0 entries.add(new CachedPDB(seq, pdbEntry));
596    }
597    }
598    }
599    }
600  3 cachedPDBExists = !entries.isEmpty();
601  3 PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
602  3 tbl_local_pdb.setModel(tableModelx);
603    }
604   
605    /**
606    * Filters a given list of discovered structures based on supplied argument
607    *
608    * @param fieldToFilterBy
609    * the field to filter by
610    */
 
611  1 toggle void filterResultSet(final String fieldToFilterBy)
612    {
613  1 Thread filterThread = new Thread(new Runnable()
614    {
615   
 
616  1 toggle @Override
617    public void run()
618    {
619  1 long startTime = System.currentTimeMillis();
620  1 lbl_loading.setVisible(true);
621  1 Collection<FTSDataColumnI> wantedFields = data.getDocFieldPrefs()
622    .getStructureSummaryFields();
623  1 Collection<FTSData> filteredResponse = new HashSet<>();
624  1 HashSet<String> errors = new HashSet<>();
625   
626  1 for (SequenceI seq : selectedSequences)
627    {
628   
629  1 FTSRestResponse resultList;
630  1 try
631    {
632  1 resultList = data.selectFirstRankedQuery(seq,
633    discoveredStructuresSet, wantedFields, fieldToFilterBy,
634    !chk_invertFilter.isSelected());
635   
636    } catch (Exception e)
637    {
638  0 Console.debugPrintStackTrace(e);
639  0 errors.add(e.getMessage());
640  0 continue;
641    }
642  1 if (resultList.getSearchSummary() != null
643    && !resultList.getSearchSummary().isEmpty())
644    {
645  0 filteredResponse.addAll(resultList.getSearchSummary());
646    }
647    }
648   
649  1 String totalTime = (System.currentTimeMillis() - startTime)
650    + " milli secs";
651  1 if (!filteredResponse.isEmpty())
652    {
653  0 final int filterResponseCount = filteredResponse.size();
654  0 Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<>();
655  0 reorderedStructuresSet.addAll(filteredResponse);
656  0 reorderedStructuresSet.addAll(discoveredStructuresSet);
657  0 getResultTable()
658    .setModel(data.getTableModel(reorderedStructuresSet));
659   
660  0 FTSRestResponse.configureTableColumn(getResultTable(),
661    wantedFields, tempUserPrefs);
662  0 getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
663  0 getResultTable().getColumn("Ref Sequence").setMinWidth(100);
664  0 getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
665    // Update table selection model here
666  0 getResultTable().addRowSelectionInterval(0,
667    filterResponseCount - 1);
668  0 mainFrame.setTitle(MessageManager.formatMessage(
669    "label.structure_chooser_filter_time", totalTime));
670    }
671    else
672    {
673  1 mainFrame.setTitle(MessageManager.formatMessage(
674    "label.structure_chooser_filter_time", totalTime));
675  1 if (errors.size() > 0)
676    {
677  0 StringBuilder errorMsg = new StringBuilder();
678  0 for (String error : errors)
679    {
680  0 errorMsg.append(error).append("\n");
681    }
682  0 JvOptionPane.showMessageDialog(null, errorMsg.toString(),
683    MessageManager.getString("label.pdb_web-service_error"),
684    JvOptionPane.ERROR_MESSAGE);
685    }
686    }
687   
688  1 lbl_loading.setVisible(false);
689   
690  1 validateSelections();
691    }
692    });
693  1 filterThread.start();
694    }
695   
696    /**
697    * Handles action event for btn_pdbFromFile
698    */
 
699  0 toggle @Override
700    protected void pdbFromFile_actionPerformed()
701    {
702    // TODO: JAL-3048 not needed for Jalview-JS until JSmol dep and
703    // StructureChooser
704    // works
705  0 JalviewFileChooser chooser = new JalviewFileChooser(
706    Cache.getProperty("LAST_DIRECTORY"));
707  0 chooser.setFileView(new JalviewFileView());
708  0 chooser.setDialogTitle(
709    MessageManager.formatMessage("label.select_pdb_file_for",
710    selectedSequence.getDisplayId(false)));
711  0 chooser.setToolTipText(MessageManager.formatMessage(
712    "label.load_pdb_file_associate_with_sequence",
713    selectedSequence.getDisplayId(false)));
714   
715  0 int value = chooser.showOpenDialog(null);
716  0 if (value == JalviewFileChooser.APPROVE_OPTION)
717    {
718  0 selectedPdbFileName = chooser.getSelectedFile().getPath();
719  0 Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
720  0 boolean guessTFType = localPdbPaeMatrixFileName == null;
721  0 localPdbPaeMatrixFileName = guessPAEFilename();
722  0 guessTFType |= localPdbPaeMatrixFileName != null;
723  0 Regex alphaFold = JmolParser.getNewAlphafoldValidator();
724  0 if (guessTFType
725    && alphaFold.search(new File(selectedPdbFileName).getName())
726    && !tempFacAsChanged)
727    {
728    // localPdbPaeMatrixFileName was null and now isn't and filename could
729    // well be AlphaFold and user hasn't adjusted the tempFacType
730  0 combo_tempFacAs.setSelectedItem(TFType.PLDDT);
731    }
732  0 validateSelections();
733    }
734    }
735   
736    /**
737    * Handles action event for btn_paeMatrixFile
738    */
 
739  0 toggle @Override
740    protected void paeMatrixFile_actionPerformed()
741    {
742  0 File pdbFile = new File(selectedPdbFileName);
743  0 String setFile = Cache.getProperty("LAST_DIRECTORY");
744  0 if (localPdbPaeMatrixFileName != null)
745    {
746  0 File paeFile = new File(localPdbPaeMatrixFileName);
747  0 if (paeFile.exists())
748  0 setFile = paeFile.getAbsolutePath();
749  0 else if (paeFile.getParentFile().exists())
750  0 setFile = paeFile.getParentFile().getAbsolutePath();
751    }
752    else
753    {
754  0 String guess = guessPAEFilename();
755  0 if (guess != null)
756  0 setFile = guess;
757    }
758  0 JalviewFileChooser chooser = new JalviewFileChooser(setFile);
759  0 chooser.setFileView(new JalviewFileView());
760  0 chooser.setDialogTitle(MessageManager.formatMessage(
761    "label.select_pae_matrix_file_for", pdbFile.getName()));
762  0 chooser.setToolTipText(MessageManager.formatMessage(
763    "label.load_pae_matrix_file_associate_with_structure",
764    pdbFile.getName()));
765   
766    // TODO convert to Callable/Promise
767  0 int value = chooser.showOpenDialog(null);
768  0 if (value == JalviewFileChooser.APPROVE_OPTION)
769    {
770  0 String fileName = chooser.getSelectedFile().getPath();
771  0 try
772    {
773  0 PAEContactMatrix.validateContactMatrixFile(fileName);
774    } catch (Exception thr)
775    {
776  0 JvOptionPane.showInternalMessageDialog(this, MessageManager
777    .formatMessage("label.couldnt_load_file", new Object[]
778    { fileName }) + "<br>" + thr.getLocalizedMessage(),
779    MessageManager.getString("label.error_loading_file"),
780    JvOptionPane.WARNING_MESSAGE);
781  0 Console.error("Couldn't import " + fileName + " as a PAE matrix",
782    thr);
783  0 return;
784    }
785  0 localPdbPaeMatrixFileName = fileName;
786  0 Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
787    }
788  0 validateAssociationFromFile();
789    }
790   
 
791  0 toggle private String guessPAEFilename()
792    {
793  0 if (selectedPdbFileName.toLowerCase(Locale.ROOT).endsWith(".pdb")
794    || selectedPdbFileName.toLowerCase(Locale.ROOT)
795    .endsWith(".cif"))
796    {
797  0 String jsonExt = selectedPdbFileName.substring(0,
798    selectedPdbFileName.length() - 4) + ".json";
799    // AlphaFold naming scheme
800  0 String guessFile1 = StringUtils.replaceLast(jsonExt, "model",
801    "predicted_aligned_error");
802    // nf-core mode naming scheme
803  0 String guessFile2 = StringUtils.replaceLast(jsonExt, ".json",
804    "_scores.json");
805  0 if (new File(guessFile1).exists())
806    {
807  0 return guessFile1;
808    }
809  0 else if (new File(jsonExt).exists())
810    {
811  0 return jsonExt;
812    }
813  0 else if (new File(guessFile2).exists())
814    {
815  0 return guessFile2;
816    }
817    }
818  0 return null;
819    }
820   
821    /**
822    * Populates the filter combo-box options dynamically depending on discovered
823    * structures
824    */
 
825  9 toggle protected void populateFilterComboBox(boolean haveData,
826    boolean cachedPDBExist)
827    {
828  9 populateFilterComboBox(haveData, cachedPDBExist, null);
829    }
830   
831    /**
832    * Populates the filter combo-box options dynamically depending on discovered
833    * structures
834    */
 
835  9 toggle protected void populateFilterComboBox(boolean haveData,
836    boolean cachedPDBExist, FilterOption lastSel)
837    {
838   
839    /*
840    * temporarily suspend the change listener behaviour
841    */
842  9 cmb_filterOption.removeItemListener(this);
843  9 int selSet = -1;
844  9 cmb_filterOption.removeAllItems();
845  9 if (haveData)
846    {
847  6 List<FilterOption> filters = data
848    .getAvailableFilterOptions(VIEWS_FILTER);
849  6 data.updateAvailableFilterOptions(VIEWS_FILTER, filters,
850    lastDiscoveredStructuresSet);
851  6 int p = 0;
852  6 for (FilterOption filter : filters)
853    {
854  39 if (lastSel != null && filter.equals(lastSel))
855    {
856  0 selSet = p;
857    }
858  39 p++;
859  39 cmb_filterOption.addItem(filter);
860    }
861    }
862   
863  9 cmb_filterOption.addItem(
864    new FilterOption(MessageManager.getString("label.enter_pdb_id"),
865    "-", VIEWS_ENTER_ID, false, null));
866  9 cmb_filterOption.addItem(
867    new FilterOption(MessageManager.getString("label.from_file"),
868    "-", VIEWS_FROM_FILE, false, null));
869  9 if (canQueryTDB && notQueriedTDBYet)
870    {
871  2 btn_queryTDB.setVisible(true);
872  2 pnl_queryTDB.setVisible(true);
873    }
874   
875  9 if (cachedPDBExist)
876    {
877  1 FilterOption cachedOption = new FilterOption(
878    MessageManager.getString("label.cached_structures"), "-",
879    VIEWS_LOCAL_PDB, false, null);
880  1 cmb_filterOption.addItem(cachedOption);
881  1 if (selSet == -1)
882    {
883  1 cmb_filterOption.setSelectedItem(cachedOption);
884    }
885    }
886  9 if (selSet > -1)
887    {
888  0 cmb_filterOption.setSelectedIndex(selSet);
889    }
890  9 cmb_filterOption.addItemListener(this);
891    }
892   
893    /**
894    * Updates the displayed view based on the selected filter option
895    */
 
896  2 toggle protected void updateCurrentView()
897    {
898  2 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
899    .getSelectedItem());
900   
901  2 if (lastSelected == selectedFilterOpt)
902    {
903    // don't need to do anything, probably
904  0 return;
905    }
906    // otherwise, record selection
907    // and update the layout and dialog accordingly
908  2 lastSelected = selectedFilterOpt;
909   
910  2 layout_switchableViews.show(pnl_switchableViews,
911    selectedFilterOpt.getView());
912  2 String filterTitle = mainFrame.getTitle();
913  2 mainFrame.setTitle(frameTitle);
914  2 chk_invertFilter.setVisible(false);
915   
916  2 if (selectedFilterOpt.getView() == VIEWS_FILTER)
917    {
918  1 mainFrame.setTitle(filterTitle);
919    // TDB Query has no invert as yet
920  1 chk_invertFilter.setVisible(selectedFilterOpt
921    .getQuerySource() instanceof PDBStructureChooserQuerySource);
922   
923  1 if (data != selectedFilterOpt.getQuerySource()
924    || data.needsRefetch(selectedFilterOpt))
925    {
926  0 data = selectedFilterOpt.getQuerySource();
927    // rebuild the views completely, since prefs will also change
928  0 tabRefresh();
929  0 return;
930    }
931    else
932    {
933  1 filterResultSet(selectedFilterOpt.getValue());
934    }
935    }
936  1 else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
937    || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
938    {
939  1 mainFrame.setTitle(MessageManager
940    .getString("label.structure_chooser_manual_association"));
941  1 idInputAssSeqPanel.loadCmbAssSeq();
942  1 fileChooserAssSeqPanel.loadCmbAssSeq();
943    }
944  2 validateSelections();
945    }
946   
947    /**
948    * Validates user selection and enables the 'Add' and 'New View' buttons if
949    * all parameters are correct (the Add button will only be visible if there is
950    * at least one existing structure viewer open). This basically means at least
951    * one structure selected and no error messages.
952    * <p>
953    * The 'Superpose Structures' option is enabled if either more than one
954    * structure is selected, or the 'Add' to existing view option is enabled, and
955    * disabled if the only option is to open a new view of a single structure.
956    */
 
957  5 toggle @Override
958    protected void validateSelections()
959    {
960  5 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
961    .getSelectedItem());
962  5 btn_add.setEnabled(false);
963  5 String currentView = selectedFilterOpt.getView();
964  5 int selectedCount = 0;
965  5 if (currentView == VIEWS_FILTER)
966    {
967  2 selectedCount = getResultTable().getSelectedRows().length;
968  2 if (selectedCount > 0)
969    {
970  0 btn_add.setEnabled(true);
971    }
972    }
973  3 else if (currentView == VIEWS_LOCAL_PDB)
974    {
975  0 selectedCount = tbl_local_pdb.getSelectedRows().length;
976  0 if (selectedCount > 0)
977    {
978  0 btn_add.setEnabled(true);
979    }
980    }
981  3 else if (currentView == VIEWS_ENTER_ID)
982    {
983  3 validateAssociationEnterPdb();
984    }
985  0 else if (currentView == VIEWS_FROM_FILE)
986    {
987  0 validateAssociationFromFile();
988    }
989   
990  5 btn_newView.setEnabled(btn_add.isEnabled());
991   
992    /*
993    * enable 'Superpose' option if more than one structure is selected,
994    * or there are view(s) available to add structure(s) to
995    */
996  5 chk_superpose
997    .setEnabled(selectedCount > 1 || targetView.getItemCount() > 0);
998    }
999   
 
1000  0 toggle @Override
1001    protected boolean showPopupFor(int selectedRow, int x, int y)
1002    {
1003  0 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1004    .getSelectedItem());
1005  0 String currentView = selectedFilterOpt.getView();
1006  0 if (currentView == VIEWS_FILTER
1007    && data instanceof ThreeDBStructureChooserQuerySource)
1008    {
1009  0 TDB_FTSData row = ((ThreeDBStructureChooserQuerySource) data)
1010    .getFTSDataFor(getResultTable(), selectedRow,
1011    discoveredStructuresSet);
1012  0 String pageUrl = row.getModelViewUrl();
1013   
1014  0 JPopupMenu popup = new JPopupMenu("3D Beacons");
1015  0 JMenuItem viewUrl = new JMenuItem("View model web page");
1016  0 if (pageUrl == null || "".equals(pageUrl.trim()))
1017    {
1018  0 viewUrl.setEnabled(false);
1019  0 viewUrl.setText("No model page available.");
1020    }
1021  0 viewUrl.addActionListener(new ActionListener()
1022    {
 
1023  0 toggle @Override
1024    public void actionPerformed(ActionEvent e)
1025    {
1026  0 Desktop.showUrl(pageUrl);
1027    }
1028    });
1029  0 popup.add(viewUrl);
1030  0 SwingUtilities.invokeLater(new Runnable()
1031    {
 
1032  0 toggle @Override
1033    public void run()
1034    {
1035  0 popup.show(getResultTable(), x, y);
1036    }
1037    });
1038  0 return true;
1039    }
1040    // event not handled by us
1041  0 return false;
1042    }
1043    /**
1044    * Validates inputs from the Manual PDB entry panel
1045    */
 
1046  3 toggle protected void validateAssociationEnterPdb()
1047    {
1048  3 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
1049    .getCmb_assSeq().getSelectedItem();
1050  3 lbl_pdbManualFetchStatus.setIcon(errorImage);
1051  3 lbl_pdbManualFetchStatus.setToolTipText("");
1052  3 if (txt_search.getText().length() > 0)
1053    {
1054  0 lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(true,
1055    MessageManager.formatMessage("info.no_pdb_entry_found_for",
1056    txt_search.getText())));
1057    }
1058   
1059  3 if (errorWarning.length() > 0)
1060    {
1061  0 lbl_pdbManualFetchStatus.setIcon(warningImage);
1062  0 lbl_pdbManualFetchStatus.setToolTipText(
1063    JvSwingUtils.wrapTooltip(true, errorWarning.toString()));
1064    }
1065   
1066  3 if (selectedSequences.length == 1 || !assSeqOpt.getName()
1067    .equalsIgnoreCase("-Select Associated Seq-"))
1068    {
1069  3 txt_search.setEnabled(true);
1070  3 if (isValidPBDEntry)
1071    {
1072  0 btn_add.setEnabled(true);
1073  0 lbl_pdbManualFetchStatus.setToolTipText("");
1074  0 lbl_pdbManualFetchStatus.setIcon(goodImage);
1075    }
1076    }
1077    else
1078    {
1079  0 txt_search.setEnabled(false);
1080  0 lbl_pdbManualFetchStatus.setIcon(errorImage);
1081    }
1082    }
1083   
1084    /**
1085    * Validates inputs for the manual PDB file selection options
1086    */
 
1087  0 toggle protected void validateAssociationFromFile()
1088    {
1089  0 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1090    .getCmb_assSeq().getSelectedItem();
1091    // lbl_fromFileStatus.setIcon(errorImage);
1092  0 String pdbFileString = "";
1093  0 String pdbFileTooltip = "";
1094  0 if (selectedSequences.length == 1 || (assSeqOpt != null && !assSeqOpt
1095    .getName().equalsIgnoreCase("-Select Associated Seq-")))
1096    {
1097  0 btn_pdbFromFile.setEnabled(true);
1098  0 if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
1099    {
1100  0 btn_add.setEnabled(true);
1101    // lbl_fromFileStatus.setIcon(goodImage);
1102  0 pdbFileString = new File(selectedPdbFileName).getName();
1103  0 pdbFileTooltip = new File(selectedPdbFileName).getAbsolutePath();
1104  0 setPdbOptionsEnabled(true);
1105    }
1106    else
1107    {
1108  0 pdbFileString = MessageManager.getString("label.none");
1109  0 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1110  0 setPdbOptionsEnabled(false);
1111    }
1112    }
1113    else
1114    {
1115  0 btn_pdbFromFile.setEnabled(false);
1116  0 setPdbOptionsEnabled(false);
1117    // lbl_fromFileStatus.setIcon(errorImage);
1118  0 pdbFileString = MessageManager.getString("label.none");
1119  0 pdbFileTooltip = MessageManager.getString("label.nothing_selected");
1120    }
1121  0 lbl_pdbFile.setText(pdbFileString);
1122  0 lbl_pdbFile.setToolTipText(pdbFileTooltip);
1123   
1124    // PAE file choice
1125  0 String paeFileString = "";
1126  0 String paeFileTooltip = "";
1127  0 if (localPdbPaeMatrixFileName != null
1128    && localPdbPaeMatrixFileName.length() > 0)
1129    {
1130  0 paeFileString = new File(localPdbPaeMatrixFileName).getName();
1131  0 paeFileTooltip = new File(localPdbPaeMatrixFileName)
1132    .getAbsolutePath();
1133    }
1134    else
1135    {
1136  0 paeFileString = MessageManager.getString("label.none");
1137  0 paeFileTooltip = MessageManager.getString("label.nothing_selected");
1138    }
1139  0 lbl_paeFile.setText(paeFileString);
1140  0 lbl_paeFile.setToolTipText(paeFileTooltip);
1141    }
1142   
 
1143  2 toggle @Override
1144    protected void cmbAssSeqStateChanged()
1145    {
1146  2 validateSelections();
1147    }
1148    private FilterOption lastSelected=null;
1149    /**
1150    * Handles the state change event for the 'filter' combo-box and 'invert'
1151    * check-box
1152    */
 
1153  0 toggle @Override
1154    protected void stateChanged(ItemEvent e)
1155    {
1156  0 if (e.getSource() instanceof JCheckBox)
1157    {
1158  0 updateCurrentView();
1159    }
1160    else
1161    {
1162  0 if (e.getStateChange() == ItemEvent.SELECTED)
1163    {
1164  0 updateCurrentView();
1165    }
1166    }
1167   
1168    }
1169   
1170    /**
1171    * select structures for viewing by their PDB IDs
1172    *
1173    * @param pdbids
1174    * @return true if structures were found and marked as selected
1175    */
 
1176  0 toggle public boolean selectStructure(String... pdbids)
1177    {
1178  0 boolean found = false;
1179   
1180  0 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1181    .getSelectedItem());
1182  0 String currentView = selectedFilterOpt.getView();
1183  0 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1184  0 : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null;
1185   
1186  0 if (restable == null)
1187    {
1188    // can't select (enter PDB ID, or load file - need to also select which
1189    // sequence to associate with)
1190  0 return false;
1191    }
1192   
1193  0 int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex();
1194  0 for (int r = 0; r < restable.getRowCount(); r++)
1195    {
1196  0 for (int p = 0; p < pdbids.length; p++)
1197    {
1198  0 if (String.valueOf(restable.getValueAt(r, pdbIdColIndex))
1199    .equalsIgnoreCase(pdbids[p]))
1200    {
1201  0 restable.setRowSelectionInterval(r, r);
1202  0 found = true;
1203    }
1204    }
1205    }
1206  0 return found;
1207    }
1208   
1209    /**
1210    * Handles the 'New View' action
1211    */
 
1212  0 toggle @Override
1213    protected void newView_ActionPerformed()
1214    {
1215  0 targetView.setSelectedItem(null);
1216  0 showStructures(false);
1217    }
1218   
1219    /**
1220    * Handles the 'Add to existing viewer' action
1221    */
 
1222  0 toggle @Override
1223    protected void add_ActionPerformed()
1224    {
1225  0 showStructures(false);
1226    }
1227   
1228    /**
1229    * structure viewer opened by this dialog, or null
1230    */
1231    private StructureViewer sViewer = null;
1232   
 
1233  0 toggle public void showStructures(boolean waitUntilFinished)
1234    {
1235   
1236  0 final StructureSelectionManager ssm = ap.getStructureSelectionManager();
1237  0 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1238  0 boolean superimpose = chk_superpose.isSelected();
1239  0 final int preferredHeight = pnl_filter.getHeight();
1240  0 btn_add.setEnabled(false);
1241  0 btn_newView.setEnabled(false);
1242  0 btn_cancel.setEnabled(false);
1243  0 actionsPanel.setEnabled(false);
1244   
1245  0 final String progress = MessageManager
1246    .getString("label.working_ellipsis");
1247  0 setProgressBar(progress, progress.hashCode());
1248  0 Runnable viewStruc = new Runnable()
1249    {
 
1250  0 toggle @Override
1251    public void run()
1252    {
1253  0 FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
1254    .getSelectedItem());
1255  0 String currentView = selectedFilterOpt.getView();
1256  0 JTable restable = (currentView == VIEWS_FILTER) ? getResultTable()
1257    : tbl_local_pdb;
1258   
1259  0 if (currentView == VIEWS_FILTER)
1260    {
1261  0 int[] selectedRows = restable.getSelectedRows();
1262  0 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1263  0 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1264  0 pdbEntriesToView = data.collectSelectedRows(restable,
1265    selectedRows, selectedSeqsToView);
1266   
1267  0 SequenceI[] selectedSeqs = selectedSeqsToView
1268    .toArray(new SequenceI[selectedSeqsToView.size()]);
1269  0 sViewer = StructureViewer.launchStructureViewer(ap, pdbEntriesToView,
1270    selectedSeqs, superimpose, theViewer, progressBar);
1271    }
1272  0 else if (currentView == VIEWS_LOCAL_PDB)
1273    {
1274  0 int[] selectedRows = tbl_local_pdb.getSelectedRows();
1275  0 PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
1276  0 int count = 0;
1277  0 int pdbIdColIndex = tbl_local_pdb.getColumn("PDB Id")
1278    .getModelIndex();
1279  0 int refSeqColIndex = tbl_local_pdb.getColumn("Ref Sequence")
1280    .getModelIndex();
1281  0 List<SequenceI> selectedSeqsToView = new ArrayList<>();
1282  0 for (int row : selectedRows)
1283    {
1284  0 PDBEntry pdbEntry = ((PDBEntryTableModel) tbl_local_pdb
1285    .getModel()).getPDBEntryAt(row).getPdbEntry();
1286   
1287  0 pdbEntriesToView[count++] = pdbEntry;
1288  0 SequenceI selectedSeq = (SequenceI) tbl_local_pdb
1289    .getValueAt(row, refSeqColIndex);
1290  0 selectedSeqsToView.add(selectedSeq);
1291    }
1292  0 SequenceI[] selectedSeqs = selectedSeqsToView
1293    .toArray(new SequenceI[selectedSeqsToView.size()]);
1294  0 sViewer = StructureViewer.launchStructureViewer(ap, pdbEntriesToView,
1295    selectedSeqs, superimpose, theViewer, progressBar);
1296    }
1297  0 else if (currentView == VIEWS_ENTER_ID)
1298    {
1299  0 SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
1300    .getCmb_assSeq().getSelectedItem()).getSequence();
1301  0 if (userSelectedSeq != null)
1302    {
1303  0 selectedSequence = userSelectedSeq;
1304    }
1305  0 String pdbIdStr = txt_search.getText();
1306  0 PDBEntry pdbEntry = selectedSequence.getPDBEntry(pdbIdStr);
1307  0 if (pdbEntry == null)
1308    {
1309  0 pdbEntry = new PDBEntry();
1310  0 if (pdbIdStr.split(":").length > 1)
1311    {
1312  0 pdbEntry.setId(pdbIdStr.split(":")[0]);
1313  0 pdbEntry.setChainCode(pdbIdStr.split(":")[1].toUpperCase(Locale.ROOT));
1314    }
1315    else
1316    {
1317  0 pdbEntry.setId(pdbIdStr);
1318    }
1319  0 pdbEntry.setType(PDBEntry.Type.PDB);
1320  0 selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
1321    }
1322   
1323  0 PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry };
1324  0 sViewer = StructureViewer.launchStructureViewer(ap, pdbEntriesToView,
1325    new SequenceI[]
1326    { selectedSequence }, superimpose, theViewer,
1327    progressBar);
1328    }
1329  0 else if (currentView == VIEWS_FROM_FILE)
1330    {
1331  0 StructureChooser sc = StructureChooser.this;
1332  0 TFType tft = (TFType) sc.combo_tempFacAs.getSelectedItem();
1333  0 String paeFilename = sc.localPdbPaeMatrixFileName;
1334  0 AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
1335    .getCmb_assSeq().getSelectedItem();
1336  0 SequenceI userSelectedSeq = assSeqOpt.getSequence();
1337  0 if (userSelectedSeq != null)
1338    {
1339  0 selectedSequence = userSelectedSeq;
1340    }
1341    // TODO: JAL-4107 - do we still need to resolve via AssociatePdbFileWithSeq ?
1342    //PDBEntry fileEntry = AssociatePdbFileWithSeq.associatePdbWithSeq(selectedPdbFileName,
1343    // DataSourceType.FILE, selectedSequence, true);
1344   
1345    // sViewer = StructureViewer.launchStructureViewer(ap, new PDBEntry[] { fileEntry },
1346    // new SequenceI[] { selectedSequence }, superimpose, theViewer,
1347    // progressBar);
1348   
1349  0 String pdbFilename = selectedPdbFileName;
1350  0 StructureChooser.openStructureFileForSequence(ssm, sc, ap,
1351    selectedSequence, true, pdbFilename, tft, paeFilename,
1352    false, true, false,
1353    getTargetedStructureViewer(ssm).getViewerType());
1354    }
1355  0 SwingUtilities.invokeLater(new Runnable()
1356    {
 
1357  0 toggle @Override
1358    public void run()
1359    {
1360  0 setProgressBar("Complete.", progress.hashCode());
1361  0 closeAction(preferredHeight);
1362  0 mainFrame.dispose();
1363    }
1364    });
1365    }
1366    };
1367  0 Thread runner = new Thread(viewStruc);
1368  0 runner.start();
1369  0 if (waitUntilFinished)
1370    {
1371  0 while (sViewer == null ? runner.isAlive()
1372  0 : (sViewer.sview == null ? true
1373    : !sViewer.sview.hasMapping()))
1374    {
1375  0 try
1376    {
1377  0 Thread.sleep(300);
1378    } catch (InterruptedException ie)
1379    {
1380   
1381    }
1382    }
1383    }
1384    }
1385   
1386    /**
1387    * Answers a structure viewer (new or existing) configured to superimpose
1388    * added structures or not according to the user's choice
1389    *
1390    * @param ssm
1391    * @return
1392    */
 
1393  36 toggle StructureViewer getTargetedStructureViewer(StructureSelectionManager ssm)
1394    {
1395  36 Object sv = targetView.getSelectedItem();
1396   
1397  36 return sv == null ? new StructureViewer(ssm) : (StructureViewer) sv;
1398    }
1399   
1400    /**
1401    * Adds PDB structures to a new or existing structure viewer
1402    *
1403    * @param ssm
1404    * @param pdbEntriesToView
1405    * @param alignPanel
1406    * @param sequences
1407    * @return
1408    */
 
1409  0 toggle private StructureViewer launchStructureViewer(
1410    StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1411    final AlignmentPanel alignPanel, SequenceI[] sequences)
1412    {
1413  0 return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
1414    sequences, null);
1415    }
1416   
 
1417  31 toggle public StructureViewer launchStructureViewer(
1418    StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1419    final AlignmentPanel alignPanel, SequenceI[] sequences,
1420    ViewerType viewerType)
1421    {
1422  31 return launchStructureViewer(ssm, pdbEntriesToView, alignPanel,
1423    sequences, viewerType, chk_superpose.isSelected());
1424    }
1425   
 
1426  36 toggle public StructureViewer launchStructureViewer(
1427    StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView,
1428    final AlignmentPanel alignPanel, SequenceI[] sequences,
1429    ViewerType viewerType, boolean thisSuperimpose)
1430    {
1431  36 long progressId = sequences.hashCode();
1432  36 setProgressBar(MessageManager
1433    .getString("status.launching_3d_structure_viewer"), progressId);
1434  36 final StructureViewer theViewer = getTargetedStructureViewer(ssm);
1435  36 theViewer.setSuperpose(thisSuperimpose);
1436   
1437    // if we're running in --headless mode make this viewer synchronous
1438  36 if (Jalview.isHeadlessMode())
1439    {
1440  2 theViewer.setAsync(false);
1441    }
1442   
1443    /*
1444    * remember user's choice of superimpose or not
1445    */
1446  36 Cache.setProperty(AUTOSUPERIMPOSE,
1447    Boolean.valueOf(thisSuperimpose).toString());
1448   
1449  36 setProgressBar(null, progressId);
1450  36 if (SiftsSettings.isMapWithSifts())
1451    {
1452  0 List<SequenceI> seqsWithoutSourceDBRef = new ArrayList<>();
1453  0 int p = 0;
1454    // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a
1455    // real PDB ID. For moment, we can also safely do this if there is already
1456    // a known mapping between the PDBEntry and the sequence.
1457  0 for (SequenceI seq : sequences)
1458    {
1459  0 PDBEntry pdbe = pdbEntriesToView[p++];
1460  0 if (pdbe != null && pdbe.getFile() != null)
1461    {
1462  0 StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
1463  0 if (smm != null && smm.length > 0)
1464    {
1465  0 for (StructureMapping sm : smm)
1466    {
1467  0 if (sm.getSequence() == seq)
1468    {
1469  0 continue;
1470    }
1471    }
1472    }
1473    }
1474  0 if (seq.getPrimaryDBRefs().isEmpty())
1475    {
1476  0 seqsWithoutSourceDBRef.add(seq);
1477  0 continue;
1478    }
1479    }
1480  0 if (!seqsWithoutSourceDBRef.isEmpty())
1481    {
1482  0 int y = seqsWithoutSourceDBRef.size();
1483  0 setProgressBar(MessageManager.formatMessage(
1484    "status.fetching_dbrefs_for_sequences_without_valid_refs",
1485    y), progressId);
1486  0 SequenceI[] seqWithoutSrcDBRef = seqsWithoutSourceDBRef
1487    .toArray(new SequenceI[y]);
1488  0 DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
1489  0 dbRefFetcher.fetchDBRefs(true);
1490   
1491  0 setProgressBar("Fetch complete.", progressId); // todo i18n
1492    }
1493    }
1494  36 if (pdbEntriesToView.length > 1)
1495    {
1496  5 setProgressBar(
1497    MessageManager.getString(
1498    "status.fetching_3d_structures_for_selected_entries"),
1499    progressId);
1500  5 theViewer.viewStructures(pdbEntriesToView, sequences, alignPanel,
1501    viewerType);
1502    }
1503    else
1504    {
1505  31 setProgressBar(MessageManager.formatMessage(
1506    "status.fetching_3d_structures_for",
1507    pdbEntriesToView[0].getId()), progressId);
1508    // Can we pass a pre-computeMappinged pdbFile?
1509  31 theViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel,
1510    viewerType);
1511    }
1512  36 setProgressBar(null, progressId);
1513    // remember the last viewer we used...
1514  36 lastTargetedView = theViewer;
1515  36 return theViewer;
1516    }
1517   
1518    /**
1519    * Populates the combo-box used in associating manually fetched structures to
1520    * a unique sequence when more than one sequence selection is made.
1521    */
 
1522  2 toggle @Override
1523    protected void populateCmbAssociateSeqOptions(
1524    JComboBox<AssociateSeqOptions> cmb_assSeq,
1525    JLabel lbl_associateSeq)
1526    {
1527  2 cmb_assSeq.removeAllItems();
1528  2 cmb_assSeq.addItem(
1529    new AssociateSeqOptions("-Select Associated Seq-", null));
1530  2 lbl_associateSeq.setVisible(false);
1531  2 if (selectedSequences.length > 1)
1532    {
1533  0 for (SequenceI seq : selectedSequences)
1534    {
1535  0 cmb_assSeq.addItem(new AssociateSeqOptions(seq));
1536    }
1537    }
1538    else
1539    {
1540  2 String seqName = selectedSequence.getDisplayId(false);
1541  2 seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
1542  2 lbl_associateSeq.setText(seqName);
1543  2 lbl_associateSeq.setVisible(true);
1544  2 cmb_assSeq.setVisible(false);
1545    }
1546    }
1547   
 
1548  3 toggle protected boolean isStructuresDiscovered()
1549    {
1550  3 return discoveredStructuresSet != null
1551    && !discoveredStructuresSet.isEmpty();
1552    }
1553   
1554    protected int PDB_ID_MIN = 3;// or: (Jalview.isJS() ? 3 : 1); // Bob proposes
1555    // this.
1556    // Doing a search for "1" or "1c" is valuable?
1557    // Those work but are enormously slow.
1558   
 
1559  0 toggle @Override
1560    protected void txt_search_ActionPerformed()
1561    {
1562  0 String text = txt_search.getText().trim();
1563  0 if (text.length() >= PDB_ID_MIN)
1564  0 new Thread()
1565    {
1566   
 
1567  0 toggle @Override
1568    public void run()
1569    {
1570  0 errorWarning.setLength(0);
1571  0 isValidPBDEntry = false;
1572  0 if (text.length() > 0)
1573    {
1574    // TODO move this pdb id search into the PDB specific
1575    // FTSSearchEngine
1576    // for moment, it will work fine as is because it is self-contained
1577  0 String searchTerm = text.toLowerCase(Locale.ROOT);
1578  0 searchTerm = searchTerm.split(":")[0];
1579    // jalview.bin.Console.outPrintln(">>>>> search term : " +
1580    // searchTerm);
1581  0 List<FTSDataColumnI> wantedFields = new ArrayList<>();
1582  0 FTSRestRequest pdbRequest = new FTSRestRequest();
1583  0 pdbRequest.setAllowEmptySeq(false);
1584  0 pdbRequest.setResponseSize(1);
1585  0 pdbRequest.setFieldToSearchBy("(pdb_id:");
1586  0 pdbRequest.setWantedFields(wantedFields);
1587  0 pdbRequest.setSearchTerm(searchTerm + ")");
1588  0 pdbRequest.setAssociatedSequence(selectedSequence);
1589  0 FTSRestClientI pdbRestClient = PDBFTSRestClient.getInstance();
1590  0 wantedFields.add(pdbRestClient.getPrimaryKeyColumn());
1591  0 FTSRestResponse resultList;
1592  0 try
1593    {
1594  0 resultList = pdbRestClient.executeRequest(pdbRequest);
1595    } catch (Exception e)
1596    {
1597  0 errorWarning.append(e.getMessage());
1598  0 return;
1599    } finally
1600    {
1601  0 validateSelections();
1602    }
1603  0 if (resultList.getSearchSummary() != null
1604    && resultList.getSearchSummary().size() > 0)
1605    {
1606  0 isValidPBDEntry = true;
1607    }
1608    }
1609  0 validateSelections();
1610    }
1611    }.start();
1612    }
1613   
 
1614  55 toggle @Override
1615    protected void tabRefresh()
1616    {
1617  55 if (selectedSequences != null)
1618    {
1619  0 lbl_loading.setVisible(true);
1620  0 Thread refreshThread = new Thread(new Runnable()
1621    {
 
1622  0 toggle @Override
1623    public void run()
1624    {
1625  0 fetchStructuresMetaData();
1626    // populateFilterComboBox(true, cachedPDBExists);
1627   
1628  0 filterResultSet(
1629    ((FilterOption) cmb_filterOption.getSelectedItem())
1630    .getValue());
1631  0 lbl_loading.setVisible(false);
1632    }
1633    });
1634  0 refreshThread.start();
1635    }
1636    }
1637   
 
1638    public class PDBEntryTableModel extends AbstractTableModel
1639    {
1640    String[] columns = { "Ref Sequence", "PDB Id", "Chain", "Type",
1641    "File" };
1642   
1643    private List<CachedPDB> pdbEntries;
1644   
 
1645  3 toggle public PDBEntryTableModel(List<CachedPDB> pdbEntries)
1646    {
1647  3 this.pdbEntries = new ArrayList<>(pdbEntries);
1648    }
1649   
 
1650  15 toggle @Override
1651    public String getColumnName(int columnIndex)
1652    {
1653  15 return columns[columnIndex];
1654    }
1655   
 
1656  18 toggle @Override
1657    public int getRowCount()
1658    {
1659  18 return pdbEntries.size();
1660    }
1661   
 
1662  18 toggle @Override
1663    public int getColumnCount()
1664    {
1665  18 return columns.length;
1666    }
1667   
 
1668  0 toggle @Override
1669    public boolean isCellEditable(int row, int column)
1670    {
1671  0 return false;
1672    }
1673   
 
1674  0 toggle @Override
1675    public Object getValueAt(int rowIndex, int columnIndex)
1676    {
1677  0 Object value = "??";
1678  0 CachedPDB entry = pdbEntries.get(rowIndex);
1679  0 switch (columnIndex)
1680    {
1681  0 case 0:
1682  0 value = entry.getSequence();
1683  0 break;
1684  0 case 1:
1685  0 value = entry.getQualifiedId();
1686  0 break;
1687  0 case 2:
1688  0 value = entry.getPdbEntry().getChainCode() == null ? "_"
1689    : entry.getPdbEntry().getChainCode();
1690  0 break;
1691  0 case 3:
1692  0 value = entry.getPdbEntry().getType();
1693  0 break;
1694  0 case 4:
1695  0 value = entry.getPdbEntry().getFile();
1696  0 break;
1697    }
1698  0 return value;
1699    }
1700   
 
1701  0 toggle @Override
1702    public Class<?> getColumnClass(int columnIndex)
1703    {
1704  0 return columnIndex == 0 ? SequenceI.class : PDBEntry.class;
1705    }
1706   
 
1707  0 toggle public CachedPDB getPDBEntryAt(int row)
1708    {
1709  0 return pdbEntries.get(row);
1710    }
1711   
1712    }
1713   
 
1714    private class CachedPDB
1715    {
1716    private SequenceI sequence;
1717   
1718    private PDBEntry pdbEntry;
1719   
 
1720  0 toggle public CachedPDB(SequenceI sequence, PDBEntry pdbEntry)
1721    {
1722  0 this.sequence = sequence;
1723  0 this.pdbEntry = pdbEntry;
1724    }
1725   
 
1726  0 toggle public String getQualifiedId()
1727    {
1728  0 if (pdbEntry.hasProvider())
1729    {
1730  0 return pdbEntry.getProvider() + ":" + pdbEntry.getId();
1731    }
1732  0 return pdbEntry.toString();
1733    }
1734   
 
1735  0 toggle public SequenceI getSequence()
1736    {
1737  0 return sequence;
1738    }
1739   
 
1740  0 toggle public PDBEntry getPdbEntry()
1741    {
1742  0 return pdbEntry;
1743    }
1744   
1745    }
1746   
1747    private IProgressIndicator progressBar;
1748   
 
1749  144 toggle @Override
1750    public void setProgressBar(String message, long id)
1751    {
1752  144 if (!Platform.isHeadless() && progressBar != null)
1753  136 progressBar.setProgressBar(message, id);
1754    }
1755   
 
1756  0 toggle @Override
1757    public void addProgressBar(long id, String message)
1758    {
1759  0 progressBar.addProgressBar(id, message);
1760    }
1761   
 
1762  0 toggle @Override
1763    public void removeProgressBar(long id)
1764    {
1765  0 progressBar.removeProgressBar(id);
1766    }
1767   
 
1768  0 toggle @Override
1769    public void registerHandler(long id, IProgressIndicatorHandler handler)
1770    {
1771  0 if (progressBar != null)
1772  0 progressBar.registerHandler(id, handler);
1773    }
1774   
 
1775  0 toggle @Override
1776    public boolean operationInProgress()
1777    {
1778  0 return progressBar == null ? false : progressBar.operationInProgress();
1779    }
1780   
 
1781  0 toggle public JalviewStructureDisplayI getOpenedStructureViewer()
1782    {
1783  0 return sViewer == null ? null : sViewer.sview;
1784    }
1785   
 
1786  0 toggle @Override
1787    protected void setFTSDocFieldPrefs(FTSDataColumnPreferences newPrefs)
1788    {
1789  0 data.setDocFieldPrefs(newPrefs);
1790   
1791    }
1792   
1793    /**
1794    *
1795    * @return true when all initialisation threads have finished and dialog is
1796    * visible
1797    */
 
1798  12 toggle public boolean isDialogVisible()
1799    {
1800  12 return mainFrame != null && data != null && cmb_filterOption != null
1801    && mainFrame.isVisible()
1802    && cmb_filterOption.getSelectedItem() != null;
1803    }
1804    /**
1805    *
1806    * @return true if the 3D-Beacons query button will/has been displayed
1807    */
 
1808  1 toggle public boolean isCanQueryTDB()
1809    {
1810  1 return canQueryTDB;
1811    }
1812   
 
1813  1 toggle public boolean isNotQueriedTDBYet()
1814    {
1815  1 return notQueriedTDBYet;
1816    }
1817   
1818    /**
1819    * Open a single structure file for a given sequence
1820    */
 
1821  0 toggle public static void openStructureFileForSequence(
1822    StructureSelectionManager ssm, StructureChooser sc,
1823    AlignmentPanel ap, SequenceI seq, boolean prompt,
1824    String sFilename, TFType tft, String paeFilename,
1825    boolean doXferSettings)
1826    {
1827  0 openStructureFileForSequence(ssm, sc, ap, seq, prompt, sFilename, tft,
1828    paeFilename, false, true, doXferSettings, null);
1829    }
1830   
1831    /**
1832    *
1833    * @param ssm
1834    * @param sc
1835    * @param ap
1836    * @param seq
1837    * @param prompt
1838    * @param sFilename
1839    * @param tft
1840    * @param paeFilename
1841    * @param forceHeadless
1842    * @param showRefAnnotations
1843    * @param doXferSettings
1844    * @param viewerType
1845    * - when not null means the viewer will be opened, providing
1846    * forceHeadless/headless is not true
1847    * @return
1848    */
 
1849  10 toggle public static StructureViewer openStructureFileForSequence(
1850    StructureSelectionManager ssm, StructureChooser sc,
1851    AlignmentPanel ap, SequenceI seq, boolean prompt,
1852    String sFilename, TFType tft, String paeFilename,
1853    boolean forceHeadless, boolean showRefAnnotations,
1854    boolean doXferSettings, ViewerType viewerType)
1855    {
1856  10 return openStructureForASequence(ssm, sc, ap, seq, prompt, sFilename,
1857    DataSourceType.FILE, tft, paeFilename, forceHeadless,
1858    showRefAnnotations, doXferSettings, viewerType);
1859    }
1860   
1861    /**
1862    * Import and view structure data for one or more sequences
1863    *
1864    * @param ssm
1865    * - null or a specific StructureSelectionManageer
1866    * @param sc
1867    * - null or a live StructureChooser instance to get data from
1868    * @param ap
1869    * - alignmentPanel to associate viewer with
1870    * @param seq
1871    * - sequence to associate structure with
1872    * @param prompt
1873    * - when true will raise an error dialog
1874    * @param strucDloc
1875    * - string resolving to structure data using strucDsoruce
1876    * @param strucDsource
1877    * - how to get data from strucDloc and paeFileSource or null if they
1878    * are file paths
1879    * @param tft
1880    * - temperature factor type for the datasource
1881    * @param paeFileSource
1882    * - a PAE matrix for the structure data
1883    * @param forceHeadless
1884    * - when true override any and all gui ops
1885    * @param showRefAnnotations
1886    * - automatically display reference annotations associated with
1887    * structure
1888    * @param doXferSettings
1889    * - TODO CLARIFY transfer specific import settings for structureData
1890    * @param viewerType
1891    * - when not null means the viewer will be opened, providing
1892    * forceHeadless/headless is not true
1893    * @return null or StructureViewer instance
1894    */
 
1895  47 toggle public static StructureViewer openStructureForASequence(
1896    StructureSelectionManager ssm, StructureChooser sc,
1897    AlignmentPanel ap, SequenceI seq, boolean prompt,
1898    String strucDloc, DataSourceType strucDsource, TFType tft,
1899    String paeFileSource, boolean forceHeadless,
1900    boolean showRefAnnotations, boolean doXferSettings,
1901    ViewerType viewerType)
1902    {
1903  47 StructureViewer sv = null;
1904  47 boolean headless = forceHeadless;
1905  47 if (sc == null)
1906    {
1907    // headless = true;
1908  47 prompt = false;
1909    // suppress structure viewer's external service queries
1910  47 sc = new StructureChooser(new SequenceI[] { seq }, seq, ap, false,
1911    true);
1912    }
1913  47 if (ssm == null)
1914    {
1915  47 ssm = ap.getStructureSelectionManager();
1916  47 StructureSelectionManager.doConfigureStructurePrefs(ssm);
1917    }
1918  47 String paeFilename = null;
1919  47 if (paeFileSource != null)
1920    {
1921  32 if (strucDsource == null || strucDsource.equals(DataSourceType.FILE))
1922    {
1923  29 paeFilename = paeFileSource;
1924    }
1925    else
1926    {
1927  3 if (DataSourceType.URL.equals(strucDsource))
1928    {
1929  3 try
1930    {
1931  3 File tfile = jalview.ws.dbsources.EBIAlfaFold
1932    .fetchAPAE_from(null, paeFileSource);
1933  3 paeFilename = tfile.getAbsolutePath();
1934    } catch (IOException ex)
1935    {
1936  0 Console.error(
1937    "Couldn't retrieve PAE file from URL " + paeFileSource,
1938    ex);
1939    }
1940   
1941    }
1942    else
1943    {
1944  0 Console.warn("Can't handle PAE data location type " + strucDsource
1945    + " for given structure " + strucDloc);
1946  0 ;
1947    }
1948    }
1949    }
1950  47 PDBEntry fileEntry = AssociatePdbFileWithSeq.associatePdbWithSeq(
1951    strucDloc,
1952  47 strucDsource != null ? strucDsource : DataSourceType.FILE, seq,
1953    prompt, Desktop.getInstance(), tft, paeFilename, doXferSettings);
1954   
1955    // if headless, "false" in the sc constructor above will avoid GUI behaviour
1956    // in sc.launchStructureViewer()
1957  47 if (!headless && !(viewerType == null))
1958    {
1959  31 sv = sc.launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
1960    new SequenceI[]
1961    { seq }, viewerType);
1962    // foo
1963  31 sv.getJalviewStructureDisplay().raiseViewer();
1964    }
1965   
1966  47 sc.mainFrame.dispose();
1967   
1968    // TODO should honor preferences - only show reference annotation that is
1969    // requested - JAL-4415 JAL-3124
1970  47 if (showRefAnnotations)
1971    {
1972  35 showReferenceAnnotationsForSequence(ap.alignFrame, seq);
1973    }
1974   
1975  47 return sv;
1976    }
1977   
 
1978  35 toggle public static void showReferenceAnnotationsForSequence(AlignFrame af,
1979    SequenceI sequence)
1980    {
1981  35 AlignViewport av = af.getCurrentView();
1982  35 AlignmentI al = av.getAlignment();
1983   
1984  35 List<SequenceI> forSequences = new ArrayList<>();
1985  35 forSequences.add(sequence);
1986  35 final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<>();
1987  35 AlignmentUtils.findAddableReferenceAnnotations(forSequences, null,
1988    candidates, al);
1989  35 final SequenceGroup selectionGroup = av.getSelectionGroup();
1990  35 AlignmentUtils.addReferenceAnnotations(candidates, al, selectionGroup);
1991  35 for (AlignmentViewPanel ap : af.getAlignPanels())
1992    {
1993    // required to readjust the height and position of the PAE
1994    // annotation
1995  35 ap.adjustAnnotationHeight();
1996    }
1997   
1998    }
1999   
 
2000  0 toggle @Override
2001    public JProgressBar getProgressBar(long id)
2002    {
2003  0 return progressBar.getProgressBar(id);
2004    }
2005   
 
2006  0 toggle @Override
2007    public String getMessage(long id)
2008    {
2009  0 return progressIndicator.getMessage(id);
2010    }
2011   
 
2012  0 toggle @Override
2013    public void setProgressBarMessage(long id, String message)
2014    {
2015  0 progressIndicator.setProgressBarMessage(id, message);
2016    }
2017    }