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