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