validate PDB selections on mouse release event
[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             for (String error : errors)
423             {
424               errorMsg.append(error).append("\n");
425             }
426             JOptionPane.showMessageDialog(null, errorMsg.toString(),
427                     "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
428           }
429         }
430
431         lbl_loading.setVisible(false);
432
433         validateSelections();
434       }
435     });
436     filterThread.start();
437   }
438
439
440   /**
441    * Handles action event for btn_pdbFromFile
442    */
443   public void pdbFromFile_actionPerformed()
444   {
445     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
446             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
447     chooser.setFileView(new jalview.io.JalviewFileView());
448     chooser.setDialogTitle(MessageManager.formatMessage(
449             "label.select_pdb_file_for", new String[]
450             { selectedSequence.getDisplayId(false) }));
451     chooser.setToolTipText(MessageManager.formatMessage(
452             "label.load_pdb_file_associate_with_sequence", new String[]
453             { selectedSequence.getDisplayId(false) }));
454
455     int value = chooser.showOpenDialog(null);
456     if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
457     {
458       selectedPdbFileName = chooser.getSelectedFile().getPath();
459       jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
460       validateSelections();
461     }
462   }
463
464   /**
465    * Populates the filter combo-box options dynamically depending on discovered
466    * structures
467    */
468   protected void populateFilterComboBox()
469   {
470     if (isStructuresDiscovered())
471     {
472       cmb_filterOption.addItem(new FilterOption("Best Quality",
473               PDBDocField.OVERALL_QUALITY.getCode(), VIEWS_FILTER));
474       cmb_filterOption.addItem(new FilterOption("Best UniProt Coverage",
475               PDBDocField.UNIPROT_COVERAGE.getCode(), VIEWS_FILTER));
476       cmb_filterOption.addItem(new FilterOption("Highest Resolution",
477               PDBDocField.RESOLUTION.getCode(), VIEWS_FILTER));
478       cmb_filterOption.addItem(new FilterOption("Highest Protein Chain",
479               PDBDocField.PROTEIN_CHAIN_COUNT.getCode(), VIEWS_FILTER));
480       cmb_filterOption.addItem(new FilterOption("Highest Bound Molecules",
481               PDBDocField.BOUND_MOLECULE_COUNT.getCode(), VIEWS_FILTER));
482       cmb_filterOption.addItem(new FilterOption("Highest Polymer Residues",
483               PDBDocField.POLYMER_RESIDUE_COUNT.getCode(), VIEWS_FILTER));
484     }
485     cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
486             VIEWS_ENTER_ID));
487     cmb_filterOption.addItem(new FilterOption("From File", "-",
488             VIEWS_FROM_FILE));
489     cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-",
490             VIEWS_LOCAL_PDB));
491   }
492
493   /**
494    * Updates the displayed view based on the selected filter option
495    */
496   protected void updateCurrentView()
497   {
498     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
499             .getSelectedItem());
500     layout_switchableViews.show(pnl_switchableViews,
501             selectedFilterOpt.getView());
502     String filterTitle = mainFrame.getTitle();
503     mainFrame.setTitle(frameTitle);
504     chk_invertFilter.setVisible(false);
505     if (selectedFilterOpt.getView() == VIEWS_FILTER)
506     {
507       mainFrame.setTitle(filterTitle);
508       chk_invertFilter.setVisible(true);
509       filterResultSet(selectedFilterOpt.getValue());
510     }
511     else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
512             || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
513     {
514       mainFrame.setTitle(filterTitle);
515       idInputAssSeqPanel.loadCmbAssSeq();
516       fileChooserAssSeqPanel.loadCmbAssSeq();
517     }
518     validateSelections();
519   }
520
521   /**
522    * Validates user selection and activates the view button if all parameters
523    * are correct
524    */
525   public void validateSelections()
526   {
527     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
528             .getSelectedItem());
529     btn_view.setEnabled(false);
530     String currentView = selectedFilterOpt.getView();
531     if (currentView == VIEWS_FILTER)
532     {
533       if (tbl_summary.getSelectedRows().length > 0)
534       {
535         btn_view.setEnabled(true);
536       }
537     }
538     else if (currentView == VIEWS_LOCAL_PDB)
539     {
540       if (tbl_local_pdb.getSelectedRows().length > 0)
541       {
542         btn_view.setEnabled(true);
543       }
544     }
545     else if (currentView == VIEWS_ENTER_ID)
546     {
547       validateAssociationEnterPdb();
548     }
549     else if (currentView == VIEWS_FROM_FILE)
550     {
551       validateAssociationFromFile();
552     }
553   }
554
555   /**
556    * Validates inputs from the Manual PDB entry panel
557    */
558   public void validateAssociationEnterPdb()
559   {
560     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
561             .getCmb_assSeq().getSelectedItem();
562     lbl_pdbManualFetchStatus.setIcon(errorImage);
563     lbl_pdbManualFetchStatus.setToolTipText("");
564     if (txt_search.getText().length() > 0)
565     {
566       lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
567               true, "No PDB entry found for \'" + txt_search.getText()
568                       + "\'"));
569     }
570
571     if (errorWarning.length() > 0)
572     {
573       lbl_pdbManualFetchStatus.setIcon(warningImage);
574       lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
575               true, errorWarning.toString()));
576     }
577
578     if (selectedSequences.length == 1
579             || !assSeqOpt.getName().equalsIgnoreCase(
580                     "-Select Associated Seq-"))
581     {
582       txt_search.setEnabled(true);
583       if (isValidPBDEntry)
584       {
585         btn_view.setEnabled(true);
586         lbl_pdbManualFetchStatus.setToolTipText("");
587         lbl_pdbManualFetchStatus.setIcon(goodImage);
588       }
589     }
590     else
591     {
592       txt_search.setEnabled(false);
593       lbl_pdbManualFetchStatus.setIcon(errorImage);
594     }
595   }
596
597   /**
598    * Validates inputs for the manual PDB file selection options
599    */
600   public void validateAssociationFromFile()
601   {
602     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
603             .getCmb_assSeq().getSelectedItem();
604     lbl_fromFileStatus.setIcon(errorImage);
605     if (selectedSequences.length == 1
606             || (assSeqOpt != null
607             && !assSeqOpt.getName().equalsIgnoreCase(
608                     "-Select Associated Seq-")))
609     {
610       btn_pdbFromFile.setEnabled(true);
611       if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
612       {
613         btn_view.setEnabled(true);
614         lbl_fromFileStatus.setIcon(goodImage);
615       }
616     }
617     else
618     {
619       btn_pdbFromFile.setEnabled(false);
620       lbl_fromFileStatus.setIcon(errorImage);
621     }
622   }
623
624   @Override
625   public void cmbAssSeqStateChanged()
626   {
627     validateSelections();
628   }
629
630   /**
631    * Handles the state change event for the 'filter' combo-box and 'invert'
632    * check-box
633    */
634   @Override
635   protected void stateChanged(ItemEvent e)
636   {
637     if (e.getSource() instanceof JCheckBox)
638     {
639       updateCurrentView();
640     }
641     else
642     {
643       if (e.getStateChange() == ItemEvent.SELECTED)
644       {
645         updateCurrentView();
646       }
647     }
648
649   }
650
651   /**
652    * Handles action event for btn_ok
653    */
654   @Override
655   public void ok_ActionPerformed()
656   {
657     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
658             .getSelectedItem());
659     String currentView = selectedFilterOpt.getView();
660     if (currentView == VIEWS_FILTER)
661     {
662       int pdbIdCol = PDBRestClient.getPDBIdColumIndex(
663               lastPdbRequest.getWantedFields(), true);
664       int[] selectedRows = tbl_summary.getSelectedRows();
665       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
666       int count = 0;
667       for (int summaryRow : selectedRows)
668       {
669         String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol)
670                 .toString();
671
672         PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
673         if (pdbEntry == null)
674         {
675           pdbEntry = new PDBEntry();
676           pdbEntry.setId(pdbIdStr);
677           pdbEntry.setType(PDBEntry.Type.PDB);
678         }
679         pdbEntriesToView[count++] = pdbEntry;
680       }
681       launchStructureViewer(ap.getStructureSelectionManager(),
682               pdbEntriesToView, ap, selectedSequences);
683     }
684     else if(currentView == VIEWS_LOCAL_PDB){
685       int[] selectedRows = tbl_local_pdb.getSelectedRows();
686       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
687       int count = 0;
688       for (int row : selectedRows)
689       {
690         String entryKey = tbl_local_pdb.getValueAt(row, 1).toString()
691                 .toLowerCase();
692         pdbEntriesToView[count++] = cachedEntryMap.get(entryKey);
693       }
694       launchStructureViewer(ap.getStructureSelectionManager(),
695               pdbEntriesToView, ap, selectedSequences);
696     }
697     else if (currentView == VIEWS_ENTER_ID)
698     {
699       SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
700               .getCmb_assSeq().getSelectedItem()).getSequence();
701       if (userSelectedSeq != null)
702       {
703         selectedSequence = userSelectedSeq;
704       }
705
706       String pdbIdStr = txt_search.getText();
707       PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
708       if (pdbEntry == null)
709       {
710         pdbEntry = new PDBEntry();
711         pdbEntry.setId(txt_search.getText());
712         pdbEntry.setType(PDBEntry.Type.PDB);
713       }
714
715       selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
716       PDBEntry[] pdbEntriesToView = new PDBEntry[]
717       { pdbEntry };
718       launchStructureViewer(ap.getStructureSelectionManager(),
719               pdbEntriesToView, ap, new SequenceI[]
720               { selectedSequence });
721     }
722     else if (currentView == VIEWS_FROM_FILE)
723     {
724       SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
725               .getCmb_assSeq().getSelectedItem()).getSequence();
726       if (userSelectedSeq != null)
727       {
728         selectedSequence = userSelectedSeq;
729       }
730       PDBEntry fileEntry = new AssociatePdbFileWithSeq()
731               .associatePdbWithSeq(
732               selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE,
733               selectedSequence, true, Desktop.instance);
734
735       launchStructureViewer(ap.getStructureSelectionManager(),
736               new PDBEntry[]
737               { fileEntry }, ap, new SequenceI[]
738               { selectedSequence });
739     }
740     mainFrame.dispose();
741   }
742
743   private void launchStructureViewer(StructureSelectionManager ssm,
744           PDBEntry[] pdbEntriesToView, AlignmentPanel alignPanel,
745           SequenceI[] selectedSequences)
746   {
747     StructureViewer sViewer = new StructureViewer(ssm);
748     if (pdbEntriesToView.length > 1)
749     {
750       sViewer.viewStructures(alignPanel, pdbEntriesToView,
751               alignPanel.av.collateForPDB(pdbEntriesToView));
752     }
753     else
754     {
755       sViewer.viewStructures(pdbEntriesToView[0], selectedSequences, null,
756               alignPanel);
757     }
758   }
759
760   /**
761    * Populates the combo-box used in associating manually fetched structures to
762    * a unique sequence when more than one sequence selection is made.
763    */
764   public void populateCmbAssociateSeqOptions(
765           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq)
766   {
767     cmb_assSeq.removeAllItems();
768     cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-",
769             null));
770     // cmb_assSeq.addItem(new AssociateSeqOptions("Auto Detect", null));
771     lbl_associateSeq.setVisible(false);
772     if (selectedSequences.length > 1)
773     {
774       for (SequenceI seq : selectedSequences)
775       {
776         cmb_assSeq.addItem(new AssociateSeqOptions(seq));
777       }
778     }
779     else
780     {
781       String seqName = selectedSequence.getDisplayId(false);
782       seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
783       lbl_associateSeq.setText(seqName);
784       lbl_associateSeq.setVisible(true);
785       cmb_assSeq.setVisible(false);
786     }
787   }
788
789   public boolean isStructuresDiscovered()
790   {
791     return structuresDiscovered;
792   }
793
794   public void setStructuresDiscovered(boolean structuresDiscovered)
795   {
796     this.structuresDiscovered = structuresDiscovered;
797   }
798
799   public Collection<PDBResponseSummary> getDiscoveredStructuresSet()
800   {
801     return discoveredStructuresSet;
802   }
803
804   @Override
805   protected void txt_search_ActionPerformed()
806   {
807     errorWarning.setLength(0);
808     isValidPBDEntry = false;
809     if (txt_search.getText().length() > 0)
810     {
811       List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
812       wantedFields.add(PDBDocField.PDB_ID);
813       PDBRestRequest pdbRequest = new PDBRestRequest();
814       pdbRequest.setAllowEmptySeq(false);
815       pdbRequest.setResponseSize(1);
816       pdbRequest.setFieldToSearchBy("(pdb_id:");
817       pdbRequest.setWantedFields(wantedFields);
818       pdbRequest.setSearchTerm(txt_search.getText() + ")");
819       pdbRequest.setAssociatedSequence(selectedSequence.getName());
820       pdbRestCleint = new PDBRestClient();
821       PDBRestResponse resultList;
822       try
823       {
824         resultList = pdbRestCleint.executeRequest(pdbRequest);
825       } catch (Exception e)
826       {
827         // JOptionPane.showMessageDialog(this, e.getMessage(),
828         // "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
829         errorWarning.append(e.getMessage());
830         return;
831       } finally
832       {
833         // System.out.println(">>>>> executing finally block");
834         validateSelections();
835       }
836       if (resultList.getSearchSummary() != null
837               && resultList.getSearchSummary().size() > 0)
838       {
839         isValidPBDEntry = true;
840       }
841     }
842     validateSelections();
843   }
844
845   @Override
846   public void tabRefresh()
847   {
848     if (selectedSequences != null)
849     {
850       Thread refreshThread = new Thread(new Runnable()
851       {
852         @Override
853         public void run()
854         {
855           fetchStructuresMetaData();
856           filterResultSet(((FilterOption) cmb_filterOption
857                   .getSelectedItem()).getValue());
858         }
859       });
860       refreshThread.start();
861     }
862   }
863
864 }