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