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