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