JAL-1745, JAL-1717 improvement to ensure cached PDB entries are unique within a seque...
[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     if (selectedSequences.length == 1
565             || !assSeqOpt.getName().equalsIgnoreCase(
566                     "-Select Associated Seq-"))
567     {
568       txt_search.setEnabled(true);
569       if (isValidPBDEntry)
570       {
571         btn_view.setEnabled(true);
572         lbl_pdbManualFetchStatus.setIcon(goodImage);
573       }
574     }
575     else
576     {
577       txt_search.setEnabled(false);
578       lbl_pdbManualFetchStatus.setIcon(errorImage);
579     }
580   }
581
582   /**
583    * Validates inputs for the manual PDB file selection options
584    */
585   public void validateAssociationFromFile()
586   {
587     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
588             .getCmb_assSeq().getSelectedItem();
589     lbl_fromFileStatus.setIcon(errorImage);
590     if (selectedSequences.length == 1
591             || (assSeqOpt != null
592             && !assSeqOpt.getName().equalsIgnoreCase(
593                     "-Select Associated Seq-")))
594     {
595       btn_pdbFromFile.setEnabled(true);
596       if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
597       {
598         btn_view.setEnabled(true);
599         lbl_fromFileStatus.setIcon(goodImage);
600       }
601     }
602     else
603     {
604       btn_pdbFromFile.setEnabled(false);
605       lbl_fromFileStatus.setIcon(errorImage);
606     }
607   }
608
609   @Override
610   public void cmbAssSeqStateChanged()
611   {
612     validateSelections();
613   }
614
615   /**
616    * Handles the state change event for the 'filter' combo-box and 'invert'
617    * check-box
618    */
619   @Override
620   protected void stateChanged(ItemEvent e)
621   {
622     if (e.getSource() instanceof JCheckBox)
623     {
624       updateCurrentView();
625     }
626     else
627     {
628       if (e.getStateChange() == ItemEvent.SELECTED)
629       {
630         updateCurrentView();
631       }
632     }
633
634   }
635
636   /**
637    * Handles action event for btn_ok
638    */
639   @Override
640   public void ok_ActionPerformed()
641   {
642     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
643             .getSelectedItem());
644     String currentView = selectedFilterOpt.getView();
645     if (currentView == VIEWS_FILTER)
646     {
647       int pdbIdCol = PDBRestClient.getPDBIdColumIndex(
648               lastPdbRequest.getWantedFields(), true);
649       int[] selectedRows = tbl_summary.getSelectedRows();
650       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
651       int count = 0;
652       for (int summaryRow : selectedRows)
653       {
654         String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol)
655                 .toString();
656
657         PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
658         if (pdbEntry == null)
659         {
660           pdbEntry = new PDBEntry();
661           pdbEntry.setId(pdbIdStr);
662           pdbEntry.setType(PDBEntry.Type.PDB);
663         }
664         pdbEntriesToView[count++] = pdbEntry;
665       }
666       launchStructureViewer(ap.getStructureSelectionManager(),
667               pdbEntriesToView, ap, selectedSequences);
668     }
669     else if(currentView == VIEWS_LOCAL_PDB){
670       int[] selectedRows = tbl_local_pdb.getSelectedRows();
671       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
672       int count = 0;
673       for (int row : selectedRows)
674       {
675         String entryKey = tbl_local_pdb.getValueAt(row, 1).toString()
676                 .toLowerCase();
677         pdbEntriesToView[count++] = cachedEntryMap.get(entryKey);
678       }
679       launchStructureViewer(ap.getStructureSelectionManager(),
680               pdbEntriesToView, ap, selectedSequences);
681     }
682     else if (currentView == VIEWS_ENTER_ID)
683     {
684       SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
685               .getCmb_assSeq().getSelectedItem()).getSequence();
686       if (userSelectedSeq != null)
687       {
688         selectedSequence = userSelectedSeq;
689       }
690
691       String pdbIdStr = txt_search.getText();
692       PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
693       if (pdbEntry == null)
694       {
695         pdbEntry = new PDBEntry();
696         pdbEntry.setId(txt_search.getText());
697         pdbEntry.setType(PDBEntry.Type.PDB);
698       }
699
700       selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
701       PDBEntry[] pdbEntriesToView = new PDBEntry[]
702       { pdbEntry };
703       launchStructureViewer(ap.getStructureSelectionManager(),
704               pdbEntriesToView, ap, new SequenceI[]
705               { selectedSequence });
706     }
707     else if (currentView == VIEWS_FROM_FILE)
708     {
709       SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
710               .getCmb_assSeq().getSelectedItem()).getSequence();
711       if (userSelectedSeq != null)
712       {
713         selectedSequence = userSelectedSeq;
714       }
715       PDBEntry fileEntry = new AssociatePdbFileWithSeq()
716               .associatePdbWithSeq(
717               selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE,
718               selectedSequence, true, Desktop.instance);
719
720       launchStructureViewer(ap.getStructureSelectionManager(),
721               new PDBEntry[]
722               { fileEntry }, ap, new SequenceI[]
723               { selectedSequence });
724     }
725     mainFrame.dispose();
726   }
727
728   private void launchStructureViewer(StructureSelectionManager ssm,
729           PDBEntry[] pdbEntriesToView, AlignmentPanel alignPanel,
730           SequenceI[] selectedSequences)
731   {
732     StructureViewer sViewer = new StructureViewer(ssm);
733     if (pdbEntriesToView.length > 1)
734     {
735       sViewer.viewStructures(alignPanel, pdbEntriesToView,
736               alignPanel.av.collateForPDB(pdbEntriesToView));
737     }
738     else
739     {
740       sViewer.viewStructures(pdbEntriesToView[0], selectedSequences, null,
741               alignPanel);
742     }
743   }
744
745   /**
746    * Populates the combo-box used in associating manually fetched structures to
747    * a unique sequence when more than one sequence selection is made.
748    */
749   public void populateCmbAssociateSeqOptions(
750           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq)
751   {
752     cmb_assSeq.removeAllItems();
753     cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-",
754             null));
755     // cmb_assSeq.addItem(new AssociateSeqOptions("Auto Detect", null));
756     lbl_associateSeq.setVisible(false);
757     if (selectedSequences.length > 1)
758     {
759       for (SequenceI seq : selectedSequences)
760       {
761         cmb_assSeq.addItem(new AssociateSeqOptions(seq));
762       }
763     }
764     else
765     {
766       String seqName = selectedSequence.getDisplayId(false);
767       seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
768       lbl_associateSeq.setText(seqName);
769       lbl_associateSeq.setVisible(true);
770       cmb_assSeq.setVisible(false);
771     }
772   }
773
774   public boolean isStructuresDiscovered()
775   {
776     return structuresDiscovered;
777   }
778
779   public void setStructuresDiscovered(boolean structuresDiscovered)
780   {
781     this.structuresDiscovered = structuresDiscovered;
782   }
783
784   public Collection<PDBResponseSummary> getDiscoveredStructuresSet()
785   {
786     return discoveredStructuresSet;
787   }
788
789   @Override
790   protected void txt_search_ActionPerformed()
791   {
792     isValidPBDEntry = false;
793     if (txt_search.getText().length() > 0)
794     {
795       List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
796       wantedFields.add(PDBDocField.PDB_ID);
797       PDBRestRequest pdbRequest = new PDBRestRequest();
798       pdbRequest.setAllowEmptySeq(false);
799       pdbRequest.setResponseSize(1);
800       pdbRequest.setFieldToSearchBy("(pdb_id:");
801       pdbRequest.setWantedFields(wantedFields);
802       pdbRequest.setSearchTerm(txt_search.getText() + ")");
803       pdbRequest.setAssociatedSequence(selectedSequence.getName());
804       pdbRestCleint = new PDBRestClient();
805       PDBRestResponse resultList;
806       try
807       {
808         resultList = pdbRestCleint.executeRequest(pdbRequest);
809       } catch (Exception e)
810       {
811         JOptionPane.showMessageDialog(this, e.getMessage(),
812                 "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
813         return;
814       } finally
815       {
816         System.out.println(">>>>> executing finally block");
817         validateSelections();
818       }
819       if (resultList.getSearchSummary() != null
820               && resultList.getSearchSummary().size() > 0)
821       {
822         isValidPBDEntry = true;
823       }
824     }
825     validateSelections();
826   }
827
828   @Override
829   public void tabRefresh()
830   {
831     if (selectedSequences != null)
832     {
833       Thread refreshThread = new Thread(new Runnable()
834       {
835         @Override
836         public void run()
837         {
838           fetchStructuresMetaData();
839           filterResultSet(((FilterOption) cmb_filterOption
840                   .getSelectedItem()).getValue());
841         }
842       });
843       refreshThread.start();
844     }
845   }
846
847
848 }