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