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