3db26f3865ccb18cd91f485026f8fbfdfe45934f
[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);
157       pdbRestCleint = new PDBRestClient();
158       PDBRestResponse resultList;
159       try
160       {
161         resultList = pdbRestCleint.executeRequest(pdbRequest);
162       } catch (Exception e)
163       {
164         e.printStackTrace();
165         errors.add(e.getMessage());
166         continue;
167       }
168       lastPdbRequest = pdbRequest;
169       if (resultList.getSearchSummary() != null
170               && !resultList.getSearchSummary().isEmpty())
171       {
172         discoveredStructuresSet.addAll(resultList.getSearchSummary());
173         updateSequencePDBEntries(seq, resultList.getSearchSummary());
174       }
175     }
176
177     int noOfStructuresFound = 0;
178     String totalTime = (System.currentTimeMillis() - startTime)
179             + " milli secs";
180     if (discoveredStructuresSet != null
181             && !discoveredStructuresSet.isEmpty())
182     {
183       tbl_summary.setModel(PDBRestResponse.getTableModel(lastPdbRequest,
184               discoveredStructuresSet));
185       structuresDiscovered = true;
186       noOfStructuresFound = discoveredStructuresSet.size();
187       mainFrame.setTitle("Structure Chooser - " + noOfStructuresFound
188               + " Found (" + totalTime + ")");
189     }
190     else
191     {
192       mainFrame
193 .setTitle("Structure Chooser - Manual association");
194       if (errors.size() > 0)
195       {
196         StringBuilder errorMsg = new StringBuilder();
197         // "Operation was unsuccessful due to the following: \n");
198         for (String error : errors)
199         {
200           errorMsg.append(error).append("\n");
201         }
202         JOptionPane.showMessageDialog(this, errorMsg.toString(),
203                 "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
204       }
205     }
206   }
207
208   public void loadLocalCachedPDBEntries()
209   {
210     DefaultTableModel tableModel = new DefaultTableModel();
211     tableModel.addColumn("Sequence");
212     tableModel.addColumn("PDB Id");
213     tableModel.addColumn("Chain");
214     tableModel.addColumn("Type");
215     tableModel.addColumn("File");
216     cachedEntryMap = new Hashtable<String, PDBEntry>();
217     for (SequenceI seq : selectedSequences)
218     {
219       if (seq.getDatasetSequence() != null
220               && seq.getDatasetSequence().getPDBId() != null)
221       {
222         for (PDBEntry pdbEntry : seq.getDatasetSequence().getPDBId())
223         {
224
225           String chain = pdbEntry.getChainCode() == null ? "_" : pdbEntry
226                   .getChainCode();
227           String[] pdbEntryRowData = new String[]
228           { seq.getDisplayId(false), pdbEntry.getId(),
229  chain,
230               pdbEntry.getType(),
231               pdbEntry.getFile() };
232           if (pdbEntry.getFile() != null)
233           {
234             tableModel.addRow(pdbEntryRowData);
235           }
236           cachedEntryMap.put(pdbEntry.getId().toLowerCase(),
237                   pdbEntry);
238         }
239       }
240     }
241     tbl_local_pdb.setModel(tableModel);
242   }
243
244   /**
245    * Update the PDBEntry for a given sequence with values retrieved from
246    * PDBResponseSummary
247    * 
248    * @param seq
249    *          the Sequence to update its DBRef entry
250    * @param responseSummaries
251    *          a collection of PDBResponseSummary
252    */
253   public void updateSequencePDBEntries(SequenceI seq,
254           Collection<PDBResponseSummary> responseSummaries)
255   {
256     for (PDBResponseSummary response : responseSummaries)
257     {
258       String pdbIdStr = response.getPdbId();
259       PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
260       if (pdbEntry == null)
261       {
262         pdbEntry = new PDBEntry();
263         pdbEntry.setId(pdbIdStr);
264         pdbEntry.setType(PDBEntry.Type.PDB);
265       }
266       seq.getDatasetSequence().addPDBId(pdbEntry);
267     }
268   }
269
270   /**
271    * Builds a query string for a given sequences using its DBRef entries
272    * 
273    * @param seq
274    *          the sequences to build a query for
275    * @return the built query string
276    */
277
278   public static String buildQuery(SequenceI seq)
279   {
280     HashSet<String> seqRefs = new LinkedHashSet<String>();
281     String seqName = seq.getName();
282     String[] names = seqName.toLowerCase().split("\\|");
283     for (String name : names)
284     {
285       // System.out.println("Found name : " + name);
286       name.trim();
287       if (isValidSeqName(name))
288       {
289         seqRefs.add(name);
290       }
291     }
292
293     if (seq.getPDBId() != null)
294     {
295       for (PDBEntry entry : seq.getPDBId())
296       {
297         if (isValidSeqName(entry.getId()))
298         {
299           seqRefs.add(entry.getId());
300         }
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         if (isValidSeqName(getDBRefId(dbRef)))
310         {
311           seqRefs.add(getDBRefId(dbRef));
312         }
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);
397           pdbRestCleint = new PDBRestClient();
398           PDBRestResponse resultList;
399           try
400           {
401             resultList = pdbRestCleint.executeRequest(pdbRequest);
402           } catch (Exception e)
403           {
404             e.printStackTrace();
405             errors.add(e.getMessage());
406             continue;
407           }
408           lastPdbRequest = pdbRequest;
409           if (resultList.getSearchSummary() != null
410                   && !resultList.getSearchSummary().isEmpty())
411           {
412             filteredResponse.addAll(resultList.getSearchSummary());
413           }
414         }
415
416         String totalTime = (System.currentTimeMillis() - startTime)
417                 + " milli secs";
418         if (!filteredResponse.isEmpty())
419         {
420           final int filterResponseCount = filteredResponse.size();
421           Collection<PDBResponseSummary> reorderedStructuresSet = new LinkedHashSet<PDBResponseSummary>();
422           reorderedStructuresSet.addAll(filteredResponse);
423           reorderedStructuresSet.addAll(discoveredStructuresSet);
424           tbl_summary.setModel(PDBRestResponse.getTableModel(
425                   lastPdbRequest, reorderedStructuresSet));
426
427           // Update table selection model here
428           tbl_summary.addRowSelectionInterval(0, filterResponseCount - 1);
429
430           mainFrame.setTitle("Structure Chooser - Filter time ("
431                   + totalTime + ")");
432         }
433         else
434         {
435           mainFrame.setTitle("Structure Chooser - Filter time ("
436                   + totalTime + ")");
437           if (errors.size() > 0)
438           {
439             StringBuilder errorMsg = new StringBuilder();
440             for (String error : errors)
441             {
442               errorMsg.append(error).append("\n");
443             }
444             JOptionPane.showMessageDialog(null, errorMsg.toString(),
445                     "PDB Web-service Error", JOptionPane.ERROR_MESSAGE);
446           }
447         }
448
449         lbl_loading.setVisible(false);
450
451         validateSelections();
452       }
453     });
454     filterThread.start();
455   }
456
457
458   /**
459    * Handles action event for btn_pdbFromFile
460    */
461   public void pdbFromFile_actionPerformed()
462   {
463     jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
464             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
465     chooser.setFileView(new jalview.io.JalviewFileView());
466     chooser.setDialogTitle(MessageManager.formatMessage(
467             "label.select_pdb_file_for", new String[]
468             { selectedSequence.getDisplayId(false) }));
469     chooser.setToolTipText(MessageManager.formatMessage(
470             "label.load_pdb_file_associate_with_sequence", new String[]
471             { selectedSequence.getDisplayId(false) }));
472
473     int value = chooser.showOpenDialog(null);
474     if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
475     {
476       selectedPdbFileName = chooser.getSelectedFile().getPath();
477       jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedPdbFileName);
478       validateSelections();
479     }
480   }
481
482   /**
483    * Populates the filter combo-box options dynamically depending on discovered
484    * structures
485    */
486   protected void populateFilterComboBox()
487   {
488     if (isStructuresDiscovered())
489     {
490       cmb_filterOption.addItem(new FilterOption("Best Quality",
491               PDBDocField.OVERALL_QUALITY.getCode(), VIEWS_FILTER));
492       cmb_filterOption.addItem(new FilterOption("Best UniProt Coverage",
493               PDBDocField.UNIPROT_COVERAGE.getCode(), VIEWS_FILTER));
494       cmb_filterOption.addItem(new FilterOption("Highest Resolution",
495               PDBDocField.RESOLUTION.getCode(), VIEWS_FILTER));
496       cmb_filterOption.addItem(new FilterOption("Highest Protein Chain",
497               PDBDocField.PROTEIN_CHAIN_COUNT.getCode(), VIEWS_FILTER));
498       cmb_filterOption.addItem(new FilterOption("Highest Bound Molecules",
499               PDBDocField.BOUND_MOLECULE_COUNT.getCode(), VIEWS_FILTER));
500       cmb_filterOption.addItem(new FilterOption("Highest Polymer Residues",
501               PDBDocField.POLYMER_RESIDUE_COUNT.getCode(), VIEWS_FILTER));
502     }
503     cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
504             VIEWS_ENTER_ID));
505     cmb_filterOption.addItem(new FilterOption("From File", "-",
506             VIEWS_FROM_FILE));
507     cmb_filterOption.addItem(new FilterOption("Cached PDB Entries", "-",
508             VIEWS_LOCAL_PDB));
509   }
510
511   /**
512    * Updates the displayed view based on the selected filter option
513    */
514   protected void updateCurrentView()
515   {
516     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
517             .getSelectedItem());
518     layout_switchableViews.show(pnl_switchableViews,
519             selectedFilterOpt.getView());
520     String filterTitle = mainFrame.getTitle();
521     mainFrame.setTitle(frameTitle);
522     chk_invertFilter.setVisible(false);
523     if (selectedFilterOpt.getView() == VIEWS_FILTER)
524     {
525       mainFrame.setTitle(filterTitle);
526       chk_invertFilter.setVisible(true);
527       filterResultSet(selectedFilterOpt.getValue());
528     }
529     else if (selectedFilterOpt.getView() == VIEWS_ENTER_ID
530             || selectedFilterOpt.getView() == VIEWS_FROM_FILE)
531     {
532       mainFrame.setTitle(filterTitle);
533       idInputAssSeqPanel.loadCmbAssSeq();
534       fileChooserAssSeqPanel.loadCmbAssSeq();
535     }
536     validateSelections();
537   }
538
539   /**
540    * Validates user selection and activates the view button if all parameters
541    * are correct
542    */
543   public void validateSelections()
544   {
545     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
546             .getSelectedItem());
547     btn_view.setEnabled(false);
548     String currentView = selectedFilterOpt.getView();
549     if (currentView == VIEWS_FILTER)
550     {
551       if (tbl_summary.getSelectedRows().length > 0)
552       {
553         btn_view.setEnabled(true);
554       }
555     }
556     else if (currentView == VIEWS_LOCAL_PDB)
557     {
558       if (tbl_local_pdb.getSelectedRows().length > 0)
559       {
560         btn_view.setEnabled(true);
561       }
562     }
563     else if (currentView == VIEWS_ENTER_ID)
564     {
565       validateAssociationEnterPdb();
566     }
567     else if (currentView == VIEWS_FROM_FILE)
568     {
569       validateAssociationFromFile();
570     }
571   }
572
573   /**
574    * Validates inputs from the Manual PDB entry panel
575    */
576   public void validateAssociationEnterPdb()
577   {
578     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) idInputAssSeqPanel
579             .getCmb_assSeq().getSelectedItem();
580     lbl_pdbManualFetchStatus.setIcon(errorImage);
581     lbl_pdbManualFetchStatus.setToolTipText("");
582     if (txt_search.getText().length() > 0)
583     {
584       lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
585               true, "No PDB entry found for \'" + txt_search.getText()
586                       + "\'"));
587     }
588
589     if (errorWarning.length() > 0)
590     {
591       lbl_pdbManualFetchStatus.setIcon(warningImage);
592       lbl_pdbManualFetchStatus.setToolTipText(JvSwingUtils.wrapTooltip(
593               true, errorWarning.toString()));
594     }
595
596     if (selectedSequences.length == 1
597             || !assSeqOpt.getName().equalsIgnoreCase(
598                     "-Select Associated Seq-"))
599     {
600       txt_search.setEnabled(true);
601       if (isValidPBDEntry)
602       {
603         btn_view.setEnabled(true);
604         lbl_pdbManualFetchStatus.setToolTipText("");
605         lbl_pdbManualFetchStatus.setIcon(goodImage);
606       }
607     }
608     else
609     {
610       txt_search.setEnabled(false);
611       lbl_pdbManualFetchStatus.setIcon(errorImage);
612     }
613   }
614
615   /**
616    * Validates inputs for the manual PDB file selection options
617    */
618   public void validateAssociationFromFile()
619   {
620     AssociateSeqOptions assSeqOpt = (AssociateSeqOptions) fileChooserAssSeqPanel
621             .getCmb_assSeq().getSelectedItem();
622     lbl_fromFileStatus.setIcon(errorImage);
623     if (selectedSequences.length == 1
624             || (assSeqOpt != null
625             && !assSeqOpt.getName().equalsIgnoreCase(
626                     "-Select Associated Seq-")))
627     {
628       btn_pdbFromFile.setEnabled(true);
629       if (selectedPdbFileName != null && selectedPdbFileName.length() > 0)
630       {
631         btn_view.setEnabled(true);
632         lbl_fromFileStatus.setIcon(goodImage);
633       }
634     }
635     else
636     {
637       btn_pdbFromFile.setEnabled(false);
638       lbl_fromFileStatus.setIcon(errorImage);
639     }
640   }
641
642   @Override
643   public void cmbAssSeqStateChanged()
644   {
645     validateSelections();
646   }
647
648   /**
649    * Handles the state change event for the 'filter' combo-box and 'invert'
650    * check-box
651    */
652   @Override
653   protected void stateChanged(ItemEvent e)
654   {
655     if (e.getSource() instanceof JCheckBox)
656     {
657       updateCurrentView();
658     }
659     else
660     {
661       if (e.getStateChange() == ItemEvent.SELECTED)
662       {
663         updateCurrentView();
664       }
665     }
666
667   }
668
669   /**
670    * Handles action event for btn_ok
671    */
672   @Override
673   public void ok_ActionPerformed()
674   {
675     FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
676             .getSelectedItem());
677     String currentView = selectedFilterOpt.getView();
678     if (currentView == VIEWS_FILTER)
679     {
680       int pdbIdColIndex = tbl_summary.getColumn(
681               PDBRestClient.PDBDocField.PDB_ID.getName()).getModelIndex();
682       int refSeqColIndex = tbl_summary.getColumn("Ref Sequence")
683               .getModelIndex();
684       int[] selectedRows = tbl_summary.getSelectedRows();
685       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
686       int count = 0;
687       ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
688       for (int summaryRow : selectedRows)
689       {
690         String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdColIndex)
691                 .toString();
692         SequenceI selectedSeq = (SequenceI) tbl_summary.getValueAt(
693                 summaryRow, refSeqColIndex);
694         selectedSeqsToView.add(selectedSeq);
695         PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
696         if (pdbEntry == null)
697         {
698           pdbEntry = new PDBEntry();
699           pdbEntry.setId(pdbIdStr);
700           pdbEntry.setType(PDBEntry.Type.PDB);
701         }
702         pdbEntriesToView[count++] = pdbEntry;
703       }
704       SequenceI[] selectedSeqs = selectedSeqsToView
705               .toArray(new SequenceI[selectedSeqsToView.size()]);
706       launchStructureViewer(ap.getStructureSelectionManager(),
707               pdbEntriesToView, ap, selectedSeqs);
708     }
709     else if(currentView == VIEWS_LOCAL_PDB){
710       int[] selectedRows = tbl_local_pdb.getSelectedRows();
711       PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
712       int count = 0;
713       for (int row : selectedRows)
714       {
715         String entryKey = tbl_local_pdb.getValueAt(row, 1).toString()
716                 .toLowerCase();
717         pdbEntriesToView[count++] = cachedEntryMap.get(entryKey);
718       }
719       launchStructureViewer(ap.getStructureSelectionManager(),
720               pdbEntriesToView, ap, selectedSequences);
721     }
722     else if (currentView == VIEWS_ENTER_ID)
723     {
724       SequenceI userSelectedSeq = ((AssociateSeqOptions) idInputAssSeqPanel
725               .getCmb_assSeq().getSelectedItem()).getSequence();
726       if (userSelectedSeq != null)
727       {
728         selectedSequence = userSelectedSeq;
729       }
730
731       String pdbIdStr = txt_search.getText();
732       PDBEntry pdbEntry = cachedEntryMap.get(pdbIdStr.toLowerCase());
733       if (pdbEntry == null)
734       {
735         pdbEntry = new PDBEntry();
736         pdbEntry.setId(txt_search.getText());
737         pdbEntry.setType(PDBEntry.Type.PDB);
738       }
739
740       selectedSequence.getDatasetSequence().addPDBId(pdbEntry);
741       PDBEntry[] pdbEntriesToView = new PDBEntry[]
742       { pdbEntry };
743       launchStructureViewer(ap.getStructureSelectionManager(),
744               pdbEntriesToView, ap, new SequenceI[]
745               { selectedSequence });
746     }
747     else if (currentView == VIEWS_FROM_FILE)
748     {
749       SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
750               .getCmb_assSeq().getSelectedItem()).getSequence();
751       if (userSelectedSeq != null)
752       {
753         selectedSequence = userSelectedSeq;
754       }
755       PDBEntry fileEntry = new AssociatePdbFileWithSeq()
756               .associatePdbWithSeq(
757               selectedPdbFileName, jalview.io.AppletFormatAdapter.FILE,
758               selectedSequence, true, Desktop.instance);
759
760       launchStructureViewer(ap.getStructureSelectionManager(),
761               new PDBEntry[]
762               { fileEntry }, ap, new SequenceI[]
763               { selectedSequence });
764     }
765     mainFrame.dispose();
766   }
767
768   private void launchStructureViewer(StructureSelectionManager ssm,
769           PDBEntry[] pdbEntriesToView, AlignmentPanel alignPanel,
770           SequenceI[] sequences)
771   {
772     StructureViewer sViewer = new StructureViewer(ssm);
773     if (pdbEntriesToView.length > 1)
774     {
775       sViewer.viewStructures(pdbEntriesToView, alignPanel.av.collateForPDB(pdbEntriesToView),
776               alignPanel);
777     }
778     else
779     {
780       sViewer.viewStructures(pdbEntriesToView[0], sequences,
781               alignPanel);
782     }
783   }
784
785   /**
786    * Populates the combo-box used in associating manually fetched structures to
787    * a unique sequence when more than one sequence selection is made.
788    */
789   public void populateCmbAssociateSeqOptions(
790           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq)
791   {
792     cmb_assSeq.removeAllItems();
793     cmb_assSeq.addItem(new AssociateSeqOptions("-Select Associated Seq-",
794             null));
795     // cmb_assSeq.addItem(new AssociateSeqOptions("Auto Detect", null));
796     lbl_associateSeq.setVisible(false);
797     if (selectedSequences.length > 1)
798     {
799       for (SequenceI seq : selectedSequences)
800       {
801         cmb_assSeq.addItem(new AssociateSeqOptions(seq));
802       }
803     }
804     else
805     {
806       String seqName = selectedSequence.getDisplayId(false);
807       seqName = seqName.length() <= 40 ? seqName : seqName.substring(0, 39);
808       lbl_associateSeq.setText(seqName);
809       lbl_associateSeq.setVisible(true);
810       cmb_assSeq.setVisible(false);
811     }
812   }
813
814   public boolean isStructuresDiscovered()
815   {
816     return structuresDiscovered;
817   }
818
819   public void setStructuresDiscovered(boolean structuresDiscovered)
820   {
821     this.structuresDiscovered = structuresDiscovered;
822   }
823
824   public Collection<PDBResponseSummary> getDiscoveredStructuresSet()
825   {
826     return discoveredStructuresSet;
827   }
828
829   @Override
830   protected void txt_search_ActionPerformed()
831   {
832     errorWarning.setLength(0);
833     isValidPBDEntry = false;
834     if (txt_search.getText().length() > 0)
835     {
836       List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
837       wantedFields.add(PDBDocField.PDB_ID);
838       PDBRestRequest pdbRequest = new PDBRestRequest();
839       pdbRequest.setAllowEmptySeq(false);
840       pdbRequest.setResponseSize(1);
841       pdbRequest.setFieldToSearchBy("(pdb_id:");
842       pdbRequest.setWantedFields(wantedFields);
843       pdbRequest.setSearchTerm(txt_search.getText() + ")");
844       pdbRequest.setAssociatedSequence(selectedSequence);
845       pdbRestCleint = new PDBRestClient();
846       PDBRestResponse resultList;
847       try
848       {
849         resultList = pdbRestCleint.executeRequest(pdbRequest);
850       } catch (Exception e)
851       {
852         errorWarning.append(e.getMessage());
853         return;
854       } finally
855       {
856         validateSelections();
857       }
858       if (resultList.getSearchSummary() != null
859               && resultList.getSearchSummary().size() > 0)
860       {
861         isValidPBDEntry = true;
862       }
863     }
864     validateSelections();
865   }
866
867   @Override
868   public void tabRefresh()
869   {
870     if (selectedSequences != null)
871     {
872       Thread refreshThread = new Thread(new Runnable()
873       {
874         @Override
875         public void run()
876         {
877           fetchStructuresMetaData();
878           filterResultSet(((FilterOption) cmb_filterOption
879                   .getSelectedItem()).getValue());
880         }
881       });
882       refreshThread.start();
883     }
884   }
885
886 }