JAL-1700 Improved the error handling mechanism for the PDB Rest client
[jalview.git] / src / jalview / gui / StructureChooser.java
1 /*
2
3  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
4  * Copyright (C) 2014 The Jalview Authors
5  * 
6  * This file is part of Jalview.
7  * 
8  * Jalview is free software: you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License 
10  * as published by the Free Software Foundation, either version 3
11  * of the License, or (at your option) any later version.
12  *  
13  * Jalview is distributed in the hope that it will be useful, but 
14  * WITHOUT ANY WARRANTY; without even the implied warranty 
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
16  * PURPOSE.  See the GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
20  * The Jalview Authors are detailed in the 'AUTHORS' file.
21  */
22
23 package jalview.gui;
24
25 import jalview.datamodel.DBRefEntry;
26 import jalview.datamodel.PDBEntry;
27 import jalview.datamodel.SequenceI;
28 import jalview.jbgui.GStructureChooser;
29 import jalview.jbgui.PDBDocFieldPreferences;
30 import jalview.structure.StructureSelectionManager;
31 import jalview.util.MessageManager;
32 import jalview.ws.dbsources.PDBRestClient;
33 import jalview.ws.dbsources.PDBRestClient.PDBDocField;
34 import jalview.ws.uimodel.PDBRestRequest;
35 import jalview.ws.uimodel.PDBRestResponse;
36 import jalview.ws.uimodel.PDBRestResponse.PDBResponseSummary;
37
38 import java.awt.event.ItemEvent;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.HashSet;
42 import java.util.Hashtable;
43 import java.util.LinkedHashSet;
44 import java.util.List;
45
46 import javax.swing.JCheckBox;
47 import javax.swing.JComboBox;
48 import javax.swing.JLabel;
49 import javax.swing.JOptionPane;
50 import javax.swing.table.DefaultTableModel;
51
52
53 /**
54  * Provides the behaviors for the Structure chooser Panel
55  * 
56  * @author tcnofoegbu
57  *
58  */
59 @SuppressWarnings("serial")
60 public class StructureChooser extends GStructureChooser
61 {
62   private boolean structuresDiscovered = false;
63
64   private SequenceI selectedSequence;
65
66   private SequenceI[] selectedSequences;
67
68   private IProgressIndicator progressIndicator;
69
70   private Collection<PDBResponseSummary> discoveredStructuresSet;
71
72   private PDBRestRequest lastPdbRequest;
73
74   private PDBRestClient pdbRestCleint;
75
76   private String selectedPdbFileName;
77
78   private boolean isValidPBDEntry;
79
80   private static Hashtable<String, PDBEntry> cachedEntryMap;
81
82   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
83           AlignmentPanel ap)
84   {
85     this.ap = ap;
86     this.selectedSequence = selectedSeq;
87     this.selectedSequences = selectedSeqs;
88     this.progressIndicator = (ap == null) ? null : ap.alignFrame;
89     init();
90   }
91
92   /**
93    * Initializes parameters used by the Structure Chooser Panel
94    */
95   public void init()
96   {
97     Thread discoverPDBStructuresThread = new Thread(new Runnable()
98     {
99       @Override
100       public void run()
101       {
102         long startTime = System.currentTimeMillis();
103         String msg = MessageManager.getString("status.fetching_db_refs");
104         updateProgressIndicator(msg, startTime);
105         loadLocalCachedPDBEntries();
106         fetchStructuresMetaData();
107         populateFilterComboBox();
108         updateProgressIndicator(null, startTime);
109         mainFrame.setVisible(true);
110         updateCurrentView();
111       }
112     });
113     discoverPDBStructuresThread.start();
114   }
115
116   /**
117    * Updates the progress indicator with the specified message
118    * 
119    * @param message
120    *          displayed message for the operation
121    * @param id
122    *          unique handle for this indicator
123    */
124   public void updateProgressIndicator(String message, long id)
125   {
126     if (progressIndicator != null)
127     {
128       progressIndicator.setProgressBar(message, id);
129     }
130   }
131
132   /**
133    * Retrieve meta-data for all the structure(s) for a given sequence(s) in a
134    * selection group
135    */
136   public void fetchStructuresMetaData()
137   {
138     long startTime = System.currentTimeMillis();
139     Collection<PDBDocField> wantedFields = PDBDocFieldPreferences
140             .getStructureSummaryFields();
141
142     discoveredStructuresSet = new LinkedHashSet<PDBResponseSummary>();
143     HashSet<String> errors = new HashSet<String>();
144     for (SequenceI seq : selectedSequences)
145     {
146       PDBRestRequest pdbRequest = new PDBRestRequest();
147       pdbRequest.setAllowEmptySeq(false);
148       pdbRequest.setResponseSize(500);
149       pdbRequest.setFieldToSearchBy("(text:");
150       pdbRequest.setWantedFields(wantedFields);
151       pdbRequest.setSearchTerm(buildQuery(seq) + ")");
152       pdbRequest.setAssociatedSequence(seq.getName());
153       pdbRestCleint = new PDBRestClient();
154       PDBRestResponse resultList;
155       try
156       {
157         resultList = pdbRestCleint.executeRequest(pdbRequest);
158       } catch (Exception e)
159       {
160         errors.add(e.getMessage());
161         continue;
162       }
163       lastPdbRequest = pdbRequest;
164       if (resultList.getSearchSummary() != null
165               && !resultList.getSearchSummary().isEmpty())
166       {
167         discoveredStructuresSet.addAll(resultList.getSearchSummary());
168         updateSequenceDbRef(seq, resultList.getSearchSummary());
169       }
170     }
171
172     int noOfStructuresFound = 0;
173     String totalTime = (System.currentTimeMillis() - startTime)
174             + " milli secs";
175     if (discoveredStructuresSet != null
176             && !discoveredStructuresSet.isEmpty())
177     {
178       tbl_summary.setModel(PDBRestResponse.getTableModel(lastPdbRequest,
179               discoveredStructuresSet));
180       structuresDiscovered = true;
181       noOfStructuresFound = discoveredStructuresSet.size();
182       mainFrame.setTitle("Structure Chooser - " + noOfStructuresFound
183               + " Found (" + totalTime + ")");
184     }
185     else
186     {
187       mainFrame
188 .setTitle("Structure Chooser - Manual association");
189       if (errors.size() > 0)
190       {
191         StringBuilder errorMsg = new StringBuilder(
192                 "Operation was unsucessful due to the following: \n");
193         for (String error : errors)
194         {
195           errorMsg.append(error).append("\n");
196         }
197         JOptionPane.showMessageDialog(this, errorMsg.toString(),
198                 "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
199       }
200     }
201   }
202
203   public void loadLocalCachedPDBEntries()
204   {
205     DefaultTableModel tableModel = new DefaultTableModel();
206     tableModel.addColumn("Sequence");
207     tableModel.addColumn("PDB Id");
208     tableModel.addColumn("Chain");
209     tableModel.addColumn("Type");
210     tableModel.addColumn("File");
211     cachedEntryMap = new Hashtable<String, PDBEntry>();
212     for (SequenceI seq : selectedSequences)
213     {
214       if (seq.getDatasetSequence() != null
215               && seq.getDatasetSequence().getPDBId() != null)
216       {
217         for (PDBEntry pdbEntry : seq.getDatasetSequence().getPDBId())
218         {
219           String chain = pdbEntry.getChainCode() == null ? "_" : pdbEntry
220                   .getChainCode();
221           String[] pdbEntryRowData = new String[]
222           { seq.getDisplayId(false), pdbEntry.getId(),
223  chain,
224               pdbEntry.getType(),
225               pdbEntry.getFile() };
226           tableModel.addRow(pdbEntryRowData);
227           cachedEntryMap.put(seq.getDisplayId(false) + pdbEntry.getId(),
228                   pdbEntry);
229         }
230       }
231     }
232     tbl_local_pdb.setModel(tableModel);
233   }
234
235   /**
236    * Update the DBRef entry for a given sequence with values retrieved from
237    * PDBResponseSummary
238    * 
239    * @param seq
240    *          the Sequence to update its DBRef entry
241    * @param responseSummaries
242    *          a collection of PDBResponseSummary
243    */
244   public void updateSequenceDbRef(SequenceI seq,
245           Collection<PDBResponseSummary> responseSummaries)
246   {
247     for (PDBResponseSummary response : responseSummaries)
248     {
249       PDBEntry newEntry = new PDBEntry();
250       newEntry.setId(response.getPdbId());
251       newEntry.setType(PDBEntry.Type.PDB);
252       seq.getDatasetSequence().addPDBId(newEntry);
253     }
254   }
255
256   /**
257    * Builds a query string for a given sequences using its DBRef entries
258    * 
259    * @param seq
260    *          the sequences to build a query for
261    * @return the built query string
262    */
263
264   public static String buildQuery(SequenceI seq)
265   {
266     HashSet<String> seqRefs = new LinkedHashSet<String>();
267     String seqName = seq.getName();
268     String[] names = seqName.toLowerCase().split("\\|");
269     for (String name : names)
270     {
271       // System.out.println("Found name : " + name);
272       name.trim();
273       if (isValidSeqName(name))
274       {
275         seqRefs.add(name);
276       }
277     }
278
279     if (seq.getPDBId() != null)
280     {
281       for (PDBEntry entry : seq.getPDBId())
282       {
283         seqRefs.add(entry.getId());
284       }
285     }
286
287     if (seq.getDBRef() != null && seq.getDBRef().length != 0)
288     {
289       int count = 0;
290       for (DBRefEntry dbRef : seq.getDBRef())
291       {
292         seqRefs.add(getDBRefId(dbRef));
293         ++count;
294         if (count > 10)
295         {
296           break;
297         }
298       }
299     }
300
301     StringBuilder queryBuilder = new StringBuilder();
302     for (String seqRef : seqRefs)
303     {
304       queryBuilder.append("text:").append(seqRef).append(" OR ");
305     }
306     int endIndex = queryBuilder.lastIndexOf(" OR ");
307     String query = queryBuilder.toString().substring(5, endIndex);
308     return query;
309   }
310
311   /**
312    * Ensures sequence ref names are not less than 3 characters and does not
313    * contain a database name
314    * 
315    * @param seqName
316    * @return
317    */
318   public static boolean isValidSeqName(String seqName)
319   {
320     String ignoreList = "pdb,uniprot";
321     if (seqName.length() < 3)
322     {
323       return false;
324     }
325     for (String ignoredEntry : ignoreList.split(","))
326     {
327       if (seqName.equalsIgnoreCase(ignoredEntry))
328       {
329         return false;
330       }
331     }
332     return true;
333   }
334
335   public static String getDBRefId(DBRefEntry dbRef)
336   {
337     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
338     return ref;
339   }
340
341   /**
342    * Filters a given list of discovered structures based on supplied argument
343    * 
344    * @param fieldToFilterBy
345    *          the field to filter by
346    */
347   public void filterResultSet(final String fieldToFilterBy)
348   {
349     Thread filterThread = new Thread(new Runnable()
350     {
351       @Override
352       public void run()
353       {
354         long startTime = System.currentTimeMillis();
355         lbl_loading.setVisible(true);
356         Collection<PDBDocField> wantedFields = PDBDocFieldPreferences
357                 .getStructureSummaryFields();
358         Collection<PDBResponseSummary> filteredResponse = new HashSet<PDBResponseSummary>();
359         HashSet<String> errors = new HashSet<String>();
360         for (SequenceI seq : selectedSequences)
361         {
362           PDBRestRequest pdbRequest = new PDBRestRequest();
363           pdbRequest.setAllowEmptySeq(false);
364           pdbRequest.setResponseSize(1);
365           pdbRequest.setFieldToSearchBy("(text:");
366           pdbRequest.setFieldToSortBy(fieldToFilterBy,
367                   !chk_invertFilter.isSelected());
368           pdbRequest.setSearchTerm(buildQuery(seq) + ")");
369           pdbRequest.setWantedFields(wantedFields);
370           pdbRequest.setAssociatedSequence(seq.getName());
371           pdbRestCleint = new PDBRestClient();
372           PDBRestResponse resultList;
373           try
374           {
375             resultList = pdbRestCleint.executeRequest(pdbRequest);
376           } catch (Exception e)
377           {
378             errors.add(e.getMessage());
379             continue;
380           }
381           lastPdbRequest = pdbRequest;
382           if (resultList.getSearchSummary() != null
383                   && !resultList.getSearchSummary().isEmpty())
384           {
385             filteredResponse.addAll(resultList.getSearchSummary());
386           }
387         }
388
389         String totalTime = (System.currentTimeMillis() - startTime)
390                 + " milli secs";
391         if (!filteredResponse.isEmpty())
392         {
393           final int filterResponseCount = filteredResponse.size();
394           Collection<PDBResponseSummary> reorderedStructuresSet = new LinkedHashSet<PDBResponseSummary>();
395           reorderedStructuresSet.addAll(filteredResponse);
396           reorderedStructuresSet.addAll(discoveredStructuresSet);
397           tbl_summary.setModel(PDBRestResponse.getTableModel(
398                   lastPdbRequest, reorderedStructuresSet));
399
400           // Update table selection model here
401           tbl_summary.addRowSelectionInterval(0, filterResponseCount - 1);
402
403           mainFrame.setTitle("Structure Chooser - Filter time ("
404                   + totalTime + ")");
405         }
406         else
407         {
408           mainFrame.setTitle("Structure Chooser - Filter time ("
409                   + totalTime + ")");
410           if (errors.size() > 0)
411           {
412             StringBuilder errorMsg = new StringBuilder(
413                     "Operation unsucessful due to the following: \n");
414             for (String error : errors)
415             {
416               errorMsg.append(error).append("\n");
417             }
418             JOptionPane.showMessageDialog(null, errorMsg.toString(),
419                     "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
420           }
421         }
422
423         lbl_loading.setVisible(false);
424
425         validateSelections();
426       }
427     });
428     filterThread.start();
429   }
430
431
432   /**
433    * Handles action event for btn_pdbFromFile
434    */
435   public void pdbFromFile_actionPerformed()
436   {
437     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
438             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
439     chooser.setFileView(new jalview.io.JalviewFileView());
440     chooser.setDialogTitle(MessageManager.formatMessage(
441             "label.select_pdb_file_for", new String[]
442             { selectedSequence.getDisplayId(false) }));
443     chooser.setToolTipText(MessageManager.formatMessage(
444             "label.load_pdb_file_associate_with_sequence", new String[]
445             { selectedSequence.getDisplayId(false) }));
446
447     int value = chooser.showOpenDialog(null);
448     if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
449     {
450       selectedPdbFileName = chooser.getSelectedFile().getPath();
451       jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
452       validateSelections();
453     }
454   }
455
456   /**
457    * Populates the filter combo-box options dynamically depending on discovered
458    * structures
459    */
460   protected void populateFilterComboBox()
461   {
462     if (isStructuresDiscovered())
463     {
464       cmb_filterOption.addItem(new FilterOption("Best Quality",
465               PDBDocField.OVERALL_QUALITY.getCode(), VIEWS_FILTER));
466       cmb_filterOption.addItem(new FilterOption("Best UniProt Coverage",
467               PDBDocField.UNIPROT_COVERAGE.getCode(), VIEWS_FILTER));
468       cmb_filterOption.addItem(new FilterOption("Highest Resolution",
469               PDBDocField.RESOLUTION.getCode(), VIEWS_FILTER));
470       cmb_filterOption.addItem(new FilterOption("Highest Protein Chain",
471               PDBDocField.PROTEIN_CHAIN_COUNT.getCode(), VIEWS_FILTER));
472       cmb_filterOption.addItem(new FilterOption("Highest Bound Molecules",
473               PDBDocField.BOUND_MOLECULE_COUNT.getCode(), VIEWS_FILTER));
474       cmb_filterOption.addItem(new FilterOption("Highest Polymer Residues",
475               PDBDocField.POLYMER_RESIDUE_COUNT.getCode(), VIEWS_FILTER));
476     }
477     cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
478             VIEWS_ENTER_ID));
479     cmb_filterOption.addItem(new FilterOption("From File", "-",
480             VIEWS_FROM_FILE));
481     cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-",
482             VIEWS_LOCAL_PDB));
483   }
484
485   /**
486    * Updates the displayed view based on the selected filter option
487    */
488   protected void updateCurrentView()
489   {
490     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
491             .getSelectedItem());
492     layout_switchableViews.show(pnl_switchableViews,
493             selectedFilterOpt.getView());
494     String filterTitle = mainFrame.getTitle();
495     mainFrame.setTitle(frameTitle);
496     chk_invertFilter.setVisible(false);
497     if (selectedFilterOpt.getView() == VIEWS_FILTER)
498     {
499       mainFrame.setTitle(filterTitle);
500       chk_invertFilter.setVisible(true);
501       filterResultSet(selectedFilterOpt.getValue());
502     }
503     else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
504             || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
505     {
506       mainFrame.setTitle(filterTitle);
507       idInputAssSeqPanel.loadCmbAssSeq();
508       fileChooserAssSeqPanel.loadCmbAssSeq();
509     }
510     validateSelections();
511   }
512
513   /**
514    * Validates user selection and activates the view button if all parameters
515    * are correct
516    */
517   public void validateSelections()
518   {
519     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
520             .getSelectedItem());
521     btn_view.setEnabled(false);
522     String currentView = selectedFilterOpt.getView();
523     if (currentView == VIEWS_FILTER)
524     {
525       if (tbl_summary.getSelectedRows().length > 0)
526       {
527         btn_view.setEnabled(true);
528       }
529     }
530     else if (currentView == VIEWS_LOCAL_PDB)
531     {
532       if (tbl_local_pdb.getSelectedRows().length > 0)
533       {
534         btn_view.setEnabled(true);
535       }
536     }
537     else if (currentView == VIEWS_ENTER_ID)
538     {
539       validateAssociationEnterPdb();
540     }
541     else if (currentView == VIEWS_FROM_FILE)
542     {
543       validateAssociationFromFile();
544     }
545   }
546
547   /**
548    * Validates inputs from the Manual PDB entry panel
549    */
550   public void validateAssociationEnterPdb()
551   {
552     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
553             .getCmb_assSeq().getSelectedItem();
554     lbl_pdbManualFetchStatus.setIcon(errorImage);
555     if (selectedSequences.length == 1
556             || !assSeqOpt.getName().equalsIgnoreCase(
557                     "-Select Associated Seq-"))
558     {
559       txt_search.setEnabled(true);
560       if (isValidPBDEntry)
561       {
562         btn_view.setEnabled(true);
563         lbl_pdbManualFetchStatus.setIcon(goodImage);
564       }
565     }
566     else
567     {
568       txt_search.setEnabled(false);
569       lbl_pdbManualFetchStatus.setIcon(errorImage);
570     }
571   }
572
573   /**
574    * Validates inputs for the manual PDB file selection options
575    */
576   public void validateAssociationFromFile()
577   {
578     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
579             .getCmb_assSeq().getSelectedItem();
580     lbl_fromFileStatus.setIcon(errorImage);
581     if (selectedSequences.length == 1
582             || (assSeqOpt != null
583             && !assSeqOpt.getName().equalsIgnoreCase(
584                     "-Select Associated Seq-")))
585     {
586       btn_pdbFromFile.setEnabled(true);
587       if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
588       {
589         btn_view.setEnabled(true);
590         lbl_fromFileStatus.setIcon(goodImage);
591       }
592     }
593     else
594     {
595       btn_pdbFromFile.setEnabled(false);
596       lbl_fromFileStatus.setIcon(errorImage);
597     }
598   }
599
600   @Override
601   public void cmbAssSeqStateChanged()
602   {
603     validateSelections();
604   }
605
606   /**
607    * Handles the state change event for the 'filter' combo-box and 'invert'
608    * check-box
609    */
610   @Override
611   protected void stateChanged(ItemEvent e)
612   {
613     if (e.getSource() instanceof JCheckBox)
614     {
615       updateCurrentView();
616     }
617     else
618     {
619       if (e.getStateChange() == ItemEvent.SELECTED)
620       {
621         updateCurrentView();
622       }
623     }
624
625   }
626
627   /**
628    * Handles action event for btn_ok
629    */
630   @Override
631   public void ok_ActionPerformed()
632   {
633     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
634             .getSelectedItem());
635     String currentView = selectedFilterOpt.getView();
636     if (currentView == VIEWS_FILTER)
637     {
638       int pdbIdCol = PDBRestClient.getPDBIdColumIndex(
639               lastPdbRequest.getWantedFields(), true);
640       int[] selectedRows = tbl_summary.getSelectedRows();
641       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
642       int count = 0;
643       for (int summaryRow : selectedRows)
644       {
645         String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol)
646                 .toString();
647         PDBEntry pdbEntry = new PDBEntry();
648         pdbEntry.setId(pdbIdStr);
649         pdbEntry.setType(PDBEntry.Type.PDB);
650         pdbEntriesToView[count++] = pdbEntry;
651       }
652
653       launchStructureViewer(ap.getStructureSelectionManager(),
654               pdbEntriesToView, ap, selectedSequences);
655     }
656     else if(currentView == VIEWS_LOCAL_PDB){
657       int[] selectedRows = tbl_local_pdb.getSelectedRows();
658       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
659       int count = 0;
660       for (int row : selectedRows)
661       {
662          String entryKey = tbl_local_pdb.getValueAt(row, 0).toString() + tbl_local_pdb.getValueAt(row, 1).toString();
663         pdbEntriesToView[count++] = cachedEntryMap.get(entryKey);
664       }
665       launchStructureViewer(ap.getStructureSelectionManager(),
666               pdbEntriesToView, ap, selectedSequences);
667     }
668     else if (currentView == VIEWS_ENTER_ID)
669     {
670       SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
671               .getCmb_assSeq().getSelectedItem()).getSequence();
672       if (userSelectedSeq != null)
673       {
674         selectedSequence = userSelectedSeq;
675       }
676       PDBEntry pdbEntry = new PDBEntry();
677       pdbEntry.setId(txt_search.getText());
678       pdbEntry.setType(PDBEntry.Type.PDB);
679       selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
680       PDBEntry[] pdbEntriesToView = new PDBEntry[]
681       { pdbEntry };
682       launchStructureViewer(ap.getStructureSelectionManager(),
683               pdbEntriesToView, ap, new SequenceI[]
684               { selectedSequence });
685     }
686     else if (currentView == VIEWS_FROM_FILE)
687     {
688       SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
689               .getCmb_assSeq().getSelectedItem()).getSequence();
690       if (userSelectedSeq != null)
691       {
692         selectedSequence = userSelectedSeq;
693       }
694       PDBEntry fileEntry = new AssociatePdbFileWithSeq()
695               .associatePdbWithSeq(
696               selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE,
697               selectedSequence, true, Desktop.instance);
698
699       launchStructureViewer(ap.getStructureSelectionManager(),
700               new PDBEntry[]
701               { fileEntry }, ap, new SequenceI[]
702               { selectedSequence });
703     }
704     mainFrame.dispose();
705   }
706
707   private void launchStructureViewer(StructureSelectionManager ssm,
708           PDBEntry[] pdbEntriesToView, AlignmentPanel alignPanel,
709           SequenceI[] selectedSequences)
710   {
711     StructureViewer sViewer = new StructureViewer(ssm);
712     if (pdbEntriesToView.length > 1)
713     {
714       sViewer.viewStructures(alignPanel, pdbEntriesToView,
715               alignPanel.av.collateForPDB(pdbEntriesToView));
716     }
717     else
718     {
719       sViewer.viewStructures(pdbEntriesToView[0], selectedSequences, null,
720               alignPanel);
721     }
722   }
723
724   /**
725    * Populates the combo-box used in associating manually fetched structures to
726    * a unique sequence when more than one sequence selection is made.
727    */
728   public void populateCmbAssociateSeqOptions(
729           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq)
730   {
731     cmb_assSeq.removeAllItems();
732     cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-",
733             null));
734     // cmb_assSeq.addItem(new AssociateSeqOptions("Auto Detect", null));
735     lbl_associateSeq.setVisible(false);
736     if (selectedSequences.length > 1)
737     {
738       for (SequenceI seq : selectedSequences)
739       {
740         cmb_assSeq.addItem(new AssociateSeqOptions(seq));
741       }
742     }
743     else
744     {
745       String seqName = selectedSequence.getDisplayId(false);
746       seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
747       lbl_associateSeq.setText(seqName);
748       lbl_associateSeq.setVisible(true);
749       cmb_assSeq.setVisible(false);
750     }
751   }
752
753   public boolean isStructuresDiscovered()
754   {
755     return structuresDiscovered;
756   }
757
758   public void setStructuresDiscovered(boolean structuresDiscovered)
759   {
760     this.structuresDiscovered = structuresDiscovered;
761   }
762
763   public Collection<PDBResponseSummary> getDiscoveredStructuresSet()
764   {
765     return discoveredStructuresSet;
766   }
767
768   @Override
769   protected void txt_search_ActionPerformed()
770   {
771     isValidPBDEntry = false;
772     if (txt_search.getText().length() > 0)
773     {
774       List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
775       wantedFields.add(PDBDocField.PDB_ID);
776       PDBRestRequest pdbRequest = new PDBRestRequest();
777       pdbRequest.setAllowEmptySeq(false);
778       pdbRequest.setResponseSize(1);
779       pdbRequest.setFieldToSearchBy("(pdb_id:");
780       pdbRequest.setWantedFields(wantedFields);
781       pdbRequest.setSearchTerm(txt_search.getText() + ")");
782       pdbRequest.setAssociatedSequence(selectedSequence.getName());
783       pdbRestCleint = new PDBRestClient();
784       PDBRestResponse resultList;
785       try
786       {
787         resultList = pdbRestCleint.executeRequest(pdbRequest);
788       } catch (Exception e)
789       {
790         JOptionPane.showMessageDialog(this, e.getMessage(),
791                 "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
792         return;
793       } finally
794       {
795         System.out.println(">>>>> executing finally block");
796         validateSelections();
797       }
798       if (resultList.getSearchSummary() != null
799               && resultList.getSearchSummary().size() > 0)
800       {
801         isValidPBDEntry = true;
802       }
803     }
804     validateSelections();
805   }
806
807   @Override
808   public void tabRefresh()
809   {
810     if (selectedSequences != null)
811     {
812       Thread refreshThread = new Thread(new Runnable()
813       {
814         @Override
815         public void run()
816         {
817           fetchStructuresMetaData();
818           filterResultSet(((FilterOption) cmb_filterOption
819                   .getSelectedItem()).getValue());
820         }
821       });
822       refreshThread.start();
823     }
824   }
825
826 }