3540cfc19b3f9680cdcef124eefec642889d3517
[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 unsuccessful 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         if (isValidSeqName(entry.getId()))
297         {
298           seqRefs.add(entry.getId());
299         }
300       }
301     }
302
303     if (seq.getDBRef() != null && seq.getDBRef().length != 0)
304     {
305       int count = 0;
306       for (DBRefEntry dbRef : seq.getDBRef())
307       {
308         if (isValidSeqName(getDBRefId(dbRef)))
309         {
310           seqRefs.add(getDBRefId(dbRef));
311         }
312         ++count;
313         if (count > 10)
314         {
315           break;
316         }
317       }
318     }
319
320     StringBuilder queryBuilder = new StringBuilder();
321     for (String seqRef : seqRefs)
322     {
323       queryBuilder.append("text:").append(seqRef).append(" OR ");
324     }
325     int endIndex = queryBuilder.lastIndexOf(" OR ");
326     String query = queryBuilder.toString().substring(5, endIndex);
327     return query;
328   }
329
330   /**
331    * Ensures sequence ref names are not less than 3 characters and does not
332    * contain a database name
333    * 
334    * @param seqName
335    * @return
336    */
337   public static boolean isValidSeqName(String seqName)
338   {
339     System.out.println("seqName : " + seqName);
340     String ignoreList = "pdb,uniprot,swiss-prot";
341     if (seqName.length() < 3)
342     {
343       return false;
344     }
345     if (seqName.contains(":"))
346     {
347       return false;
348     }
349     seqName = seqName.toLowerCase();
350     for (String ignoredEntry : ignoreList.split(","))
351     {
352       if (seqName.contains(ignoredEntry))
353       {
354         return false;
355       }
356     }
357     return true;
358   }
359
360   public static String getDBRefId(DBRefEntry dbRef)
361   {
362     String ref = dbRef.getAccessionId().replaceAll("GO:", "");
363     return ref;
364   }
365
366   /**
367    * Filters a given list of discovered structures based on supplied argument
368    * 
369    * @param fieldToFilterBy
370    *          the field to filter by
371    */
372   public void filterResultSet(final String fieldToFilterBy)
373   {
374     Thread filterThread = new Thread(new Runnable()
375     {
376       @Override
377       public void run()
378       {
379         long startTime = System.currentTimeMillis();
380         lbl_loading.setVisible(true);
381         Collection<PDBDocField> wantedFields = PDBDocFieldPreferences
382                 .getStructureSummaryFields();
383         Collection<PDBResponseSummary> filteredResponse = new HashSet<PDBResponseSummary>();
384         HashSet<String> errors = new HashSet<String>();
385         for (SequenceI seq : selectedSequences)
386         {
387           PDBRestRequest pdbRequest = new PDBRestRequest();
388           pdbRequest.setAllowEmptySeq(false);
389           pdbRequest.setResponseSize(1);
390           pdbRequest.setFieldToSearchBy("(text:");
391           pdbRequest.setFieldToSortBy(fieldToFilterBy,
392                   !chk_invertFilter.isSelected());
393           pdbRequest.setSearchTerm(buildQuery(seq) + ")");
394           pdbRequest.setWantedFields(wantedFields);
395           pdbRequest.setAssociatedSequence(seq.getName());
396           pdbRestCleint = new PDBRestClient();
397           PDBRestResponse resultList;
398           try
399           {
400             resultList = pdbRestCleint.executeRequest(pdbRequest);
401           } catch (Exception e)
402           {
403             errors.add(e.getMessage());
404             continue;
405           }
406           lastPdbRequest = pdbRequest;
407           if (resultList.getSearchSummary() != null
408                   && !resultList.getSearchSummary().isEmpty())
409           {
410             filteredResponse.addAll(resultList.getSearchSummary());
411           }
412         }
413
414         String totalTime = (System.currentTimeMillis() - startTime)
415                 + " milli secs";
416         if (!filteredResponse.isEmpty())
417         {
418           final int filterResponseCount = filteredResponse.size();
419           Collection<PDBResponseSummary> reorderedStructuresSet = new LinkedHashSet<PDBResponseSummary>();
420           reorderedStructuresSet.addAll(filteredResponse);
421           reorderedStructuresSet.addAll(discoveredStructuresSet);
422           tbl_summary.setModel(PDBRestResponse.getTableModel(
423                   lastPdbRequest, reorderedStructuresSet));
424
425           // Update table selection model here
426           tbl_summary.addRowSelectionInterval(0, filterResponseCount - 1);
427
428           mainFrame.setTitle("Structure Chooser - Filter time ("
429                   + totalTime + ")");
430         }
431         else
432         {
433           mainFrame.setTitle("Structure Chooser - Filter time ("
434                   + totalTime + ")");
435           if (errors.size() > 0)
436           {
437             StringBuilder errorMsg = new StringBuilder();
438             for (String error : errors)
439             {
440               errorMsg.append(error).append("\n");
441             }
442             JOptionPane.showMessageDialog(null, errorMsg.toString(),
443                     "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
444           }
445         }
446
447         lbl_loading.setVisible(false);
448
449         validateSelections();
450       }
451     });
452     filterThread.start();
453   }
454
455
456   /**
457    * Handles action event for btn_pdbFromFile
458    */
459   public void pdbFromFile_actionPerformed()
460   {
461     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
462             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
463     chooser.setFileView(new jalview.io.JalviewFileView());
464     chooser.setDialogTitle(MessageManager.formatMessage(
465             "label.select_pdb_file_for", new String[]
466             { selectedSequence.getDisplayId(false) }));
467     chooser.setToolTipText(MessageManager.formatMessage(
468             "label.load_pdb_file_associate_with_sequence", new String[]
469             { selectedSequence.getDisplayId(false) }));
470
471     int value = chooser.showOpenDialog(null);
472     if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
473     {
474       selectedPdbFileName = chooser.getSelectedFile().getPath();
475       jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
476       validateSelections();
477     }
478   }
479
480   /**
481    * Populates the filter combo-box options dynamically depending on discovered
482    * structures
483    */
484   protected void populateFilterComboBox()
485   {
486     if (isStructuresDiscovered())
487     {
488       cmb_filterOption.addItem(new FilterOption("Best Quality",
489               PDBDocField.OVERALL_QUALITY.getCode(), VIEWS_FILTER));
490       cmb_filterOption.addItem(new FilterOption("Best UniProt Coverage",
491               PDBDocField.UNIPROT_COVERAGE.getCode(), VIEWS_FILTER));
492       cmb_filterOption.addItem(new FilterOption("Highest Resolution",
493               PDBDocField.RESOLUTION.getCode(), VIEWS_FILTER));
494       cmb_filterOption.addItem(new FilterOption("Highest Protein Chain",
495               PDBDocField.PROTEIN_CHAIN_COUNT.getCode(), VIEWS_FILTER));
496       cmb_filterOption.addItem(new FilterOption("Highest Bound Molecules",
497               PDBDocField.BOUND_MOLECULE_COUNT.getCode(), VIEWS_FILTER));
498       cmb_filterOption.addItem(new FilterOption("Highest Polymer Residues",
499               PDBDocField.POLYMER_RESIDUE_COUNT.getCode(), VIEWS_FILTER));
500     }
501     cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
502             VIEWS_ENTER_ID));
503     cmb_filterOption.addItem(new FilterOption("From File", "-",
504             VIEWS_FROM_FILE));
505     cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-",
506             VIEWS_LOCAL_PDB));
507   }
508
509   /**
510    * Updates the displayed view based on the selected filter option
511    */
512   protected void updateCurrentView()
513   {
514     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
515             .getSelectedItem());
516     layout_switchableViews.show(pnl_switchableViews,
517             selectedFilterOpt.getView());
518     String filterTitle = mainFrame.getTitle();
519     mainFrame.setTitle(frameTitle);
520     chk_invertFilter.setVisible(false);
521     if (selectedFilterOpt.getView() == VIEWS_FILTER)
522     {
523       mainFrame.setTitle(filterTitle);
524       chk_invertFilter.setVisible(true);
525       filterResultSet(selectedFilterOpt.getValue());
526     }
527     else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
528             || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
529     {
530       mainFrame.setTitle(filterTitle);
531       idInputAssSeqPanel.loadCmbAssSeq();
532       fileChooserAssSeqPanel.loadCmbAssSeq();
533     }
534     validateSelections();
535   }
536
537   /**
538    * Validates user selection and activates the view button if all parameters
539    * are correct
540    */
541   public void validateSelections()
542   {
543     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
544             .getSelectedItem());
545     btn_view.setEnabled(false);
546     String currentView = selectedFilterOpt.getView();
547     if (currentView == VIEWS_FILTER)
548     {
549       if (tbl_summary.getSelectedRows().length > 0)
550       {
551         btn_view.setEnabled(true);
552       }
553     }
554     else if (currentView == VIEWS_LOCAL_PDB)
555     {
556       if (tbl_local_pdb.getSelectedRows().length > 0)
557       {
558         btn_view.setEnabled(true);
559       }
560     }
561     else if (currentView == VIEWS_ENTER_ID)
562     {
563       validateAssociationEnterPdb();
564     }
565     else if (currentView == VIEWS_FROM_FILE)
566     {
567       validateAssociationFromFile();
568     }
569   }
570
571   /**
572    * Validates inputs from the Manual PDB entry panel
573    */
574   public void validateAssociationEnterPdb()
575   {
576     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
577             .getCmb_assSeq().getSelectedItem();
578     lbl_pdbManualFetchStatus.setIcon(errorImage);
579     lbl_pdbManualFetchStatus.setToolTipText("");
580     if (txt_search.getText().length() > 0)
581     {
582       lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
583               true, "No PDB entry found for \'" + txt_search.getText()
584                       + "\'"));
585     }
586
587     if (errorWarning.length() > 0)
588     {
589       lbl_pdbManualFetchStatus.setIcon(warningImage);
590       lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
591               true, errorWarning.toString()));
592     }
593
594     if (selectedSequences.length == 1
595             || !assSeqOpt.getName().equalsIgnoreCase(
596                     "-Select Associated Seq-"))
597     {
598       txt_search.setEnabled(true);
599       if (isValidPBDEntry)
600       {
601         btn_view.setEnabled(true);
602         lbl_pdbManualFetchStatus.setToolTipText("");
603         lbl_pdbManualFetchStatus.setIcon(goodImage);
604       }
605     }
606     else
607     {
608       txt_search.setEnabled(false);
609       lbl_pdbManualFetchStatus.setIcon(errorImage);
610     }
611   }
612
613   /**
614    * Validates inputs for the manual PDB file selection options
615    */
616   public void validateAssociationFromFile()
617   {
618     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
619             .getCmb_assSeq().getSelectedItem();
620     lbl_fromFileStatus.setIcon(errorImage);
621     if (selectedSequences.length == 1
622             || (assSeqOpt != null
623             && !assSeqOpt.getName().equalsIgnoreCase(
624                     "-Select Associated Seq-")))
625     {
626       btn_pdbFromFile.setEnabled(true);
627       if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
628       {
629         btn_view.setEnabled(true);
630         lbl_fromFileStatus.setIcon(goodImage);
631       }
632     }
633     else
634     {
635       btn_pdbFromFile.setEnabled(false);
636       lbl_fromFileStatus.setIcon(errorImage);
637     }
638   }
639
640   @Override
641   public void cmbAssSeqStateChanged()
642   {
643     validateSelections();
644   }
645
646   /**
647    * Handles the state change event for the 'filter' combo-box and 'invert'
648    * check-box
649    */
650   @Override
651   protected void stateChanged(ItemEvent e)
652   {
653     if (e.getSource() instanceof JCheckBox)
654     {
655       updateCurrentView();
656     }
657     else
658     {
659       if (e.getStateChange() == ItemEvent.SELECTED)
660       {
661         updateCurrentView();
662       }
663     }
664
665   }
666
667   /**
668    * Handles action event for btn_ok
669    */
670   @Override
671   public void ok_ActionPerformed()
672   {
673     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
674             .getSelectedItem());
675     String currentView = selectedFilterOpt.getView();
676     if (currentView == VIEWS_FILTER)
677     {
678       int pdbIdCol = PDBRestClient.getPDBIdColumIndex(
679               lastPdbRequest.getWantedFields(), true);
680       int[] selectedRows = tbl_summary.getSelectedRows();
681       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
682       int count = 0;
683       for (int summaryRow : selectedRows)
684       {
685         String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol)
686                 .toString();
687
688         PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
689         if (pdbEntry == null)
690         {
691           pdbEntry = new PDBEntry();
692           pdbEntry.setId(pdbIdStr);
693           pdbEntry.setType(PDBEntry.Type.PDB);
694         }
695         pdbEntriesToView[count++] = pdbEntry;
696       }
697       launchStructureViewer(ap.getStructureSelectionManager(),
698               pdbEntriesToView, ap, selectedSequences);
699     }
700     else if(currentView == VIEWS_LOCAL_PDB){
701       int[] selectedRows = tbl_local_pdb.getSelectedRows();
702       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
703       int count = 0;
704       for (int row : selectedRows)
705       {
706         String entryKey = tbl_local_pdb.getValueAt(row, 1).toString()
707                 .toLowerCase();
708         pdbEntriesToView[count++] = cachedEntryMap.get(entryKey);
709       }
710       launchStructureViewer(ap.getStructureSelectionManager(),
711               pdbEntriesToView, ap, selectedSequences);
712     }
713     else if (currentView == VIEWS_ENTER_ID)
714     {
715       SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
716               .getCmb_assSeq().getSelectedItem()).getSequence();
717       if (userSelectedSeq != null)
718       {
719         selectedSequence = userSelectedSeq;
720       }
721
722       String pdbIdStr = txt_search.getText();
723       PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
724       if (pdbEntry == null)
725       {
726         pdbEntry = new PDBEntry();
727         pdbEntry.setId(txt_search.getText());
728         pdbEntry.setType(PDBEntry.Type.PDB);
729       }
730
731       selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
732       PDBEntry[] pdbEntriesToView = new PDBEntry[]
733       { pdbEntry };
734       launchStructureViewer(ap.getStructureSelectionManager(),
735               pdbEntriesToView, ap, new SequenceI[]
736               { selectedSequence });
737     }
738     else if (currentView == VIEWS_FROM_FILE)
739     {
740       SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
741               .getCmb_assSeq().getSelectedItem()).getSequence();
742       if (userSelectedSeq != null)
743       {
744         selectedSequence = userSelectedSeq;
745       }
746       PDBEntry fileEntry = new AssociatePdbFileWithSeq()
747               .associatePdbWithSeq(
748               selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE,
749               selectedSequence, true, Desktop.instance);
750
751       launchStructureViewer(ap.getStructureSelectionManager(),
752               new PDBEntry[]
753               { fileEntry }, ap, new SequenceI[]
754               { selectedSequence });
755     }
756     mainFrame.dispose();
757   }
758
759   private void launchStructureViewer(StructureSelectionManager ssm,
760           PDBEntry[] pdbEntriesToView, AlignmentPanel alignPanel,
761           SequenceI[] sequences)
762   {
763     StructureViewer sViewer = new StructureViewer(ssm);
764     if (pdbEntriesToView.length > 1)
765     {
766       sViewer.viewStructures(pdbEntriesToView, alignPanel.av.collateForPDB(pdbEntriesToView),
767               alignPanel);
768     }
769     else
770     {
771       sViewer.viewStructures(pdbEntriesToView[0], sequences,
772               alignPanel);
773     }
774   }
775
776   /**
777    * Populates the combo-box used in associating manually fetched structures to
778    * a unique sequence when more than one sequence selection is made.
779    */
780   public void populateCmbAssociateSeqOptions(
781           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq)
782   {
783     cmb_assSeq.removeAllItems();
784     cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-",
785             null));
786     // cmb_assSeq.addItem(new AssociateSeqOptions("Auto Detect", null));
787     lbl_associateSeq.setVisible(false);
788     if (selectedSequences.length > 1)
789     {
790       for (SequenceI seq : selectedSequences)
791       {
792         cmb_assSeq.addItem(new AssociateSeqOptions(seq));
793       }
794     }
795     else
796     {
797       String seqName = selectedSequence.getDisplayId(false);
798       seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
799       lbl_associateSeq.setText(seqName);
800       lbl_associateSeq.setVisible(true);
801       cmb_assSeq.setVisible(false);
802     }
803   }
804
805   public boolean isStructuresDiscovered()
806   {
807     return structuresDiscovered;
808   }
809
810   public void setStructuresDiscovered(boolean structuresDiscovered)
811   {
812     this.structuresDiscovered = structuresDiscovered;
813   }
814
815   public Collection<PDBResponseSummary> getDiscoveredStructuresSet()
816   {
817     return discoveredStructuresSet;
818   }
819
820   @Override
821   protected void txt_search_ActionPerformed()
822   {
823     errorWarning.setLength(0);
824     isValidPBDEntry = false;
825     if (txt_search.getText().length() > 0)
826     {
827       List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
828       wantedFields.add(PDBDocField.PDB_ID);
829       PDBRestRequest pdbRequest = new PDBRestRequest();
830       pdbRequest.setAllowEmptySeq(false);
831       pdbRequest.setResponseSize(1);
832       pdbRequest.setFieldToSearchBy("(pdb_id:");
833       pdbRequest.setWantedFields(wantedFields);
834       pdbRequest.setSearchTerm(txt_search.getText() + ")");
835       pdbRequest.setAssociatedSequence(selectedSequence.getName());
836       pdbRestCleint = new PDBRestClient();
837       PDBRestResponse resultList;
838       try
839       {
840         resultList = pdbRestCleint.executeRequest(pdbRequest);
841       } catch (Exception e)
842       {
843         errorWarning.append(e.getMessage());
844         return;
845       } finally
846       {
847         validateSelections();
848       }
849       if (resultList.getSearchSummary() != null
850               && resultList.getSearchSummary().size() > 0)
851       {
852         isValidPBDEntry = true;
853       }
854     }
855     validateSelections();
856   }
857
858   @Override
859   public void tabRefresh()
860   {
861     if (selectedSequences != null)
862     {
863       Thread refreshThread = new Thread(new Runnable()
864       {
865         @Override
866         public void run()
867         {
868           fetchStructuresMetaData();
869           filterResultSet(((FilterOption) cmb_filterOption
870                   .getSelectedItem()).getValue());
871         }
872       });
873       refreshThread.start();
874     }
875   }
876
877 }