JAL-2944 combo box to pick which viewer to load structures into
[jalview.git] / src / jalview / jbgui / GStructureChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21
22 package jalview.jbgui;
23
24 import jalview.datamodel.SequenceI;
25 import jalview.fts.api.FTSDataColumnI;
26 import jalview.fts.core.FTSDataColumnPreferences;
27 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
28 import jalview.fts.service.pdb.PDBFTSRestClient;
29 import jalview.gui.AlignmentPanel;
30 import jalview.gui.Desktop;
31 import jalview.gui.JvSwingUtils;
32 import jalview.gui.StructureViewer;
33 import jalview.util.MessageManager;
34
35 import java.awt.BorderLayout;
36 import java.awt.CardLayout;
37 import java.awt.Component;
38 import java.awt.Dimension;
39 import java.awt.FlowLayout;
40 import java.awt.GridLayout;
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ItemEvent;
43 import java.awt.event.ItemListener;
44 import java.awt.event.KeyAdapter;
45 import java.awt.event.KeyEvent;
46 import java.awt.event.MouseAdapter;
47 import java.awt.event.MouseEvent;
48 import java.util.Arrays;
49 import java.util.HashMap;
50 import java.util.Map;
51
52 import javax.swing.ImageIcon;
53 import javax.swing.JButton;
54 import javax.swing.JCheckBox;
55 import javax.swing.JComboBox;
56 import javax.swing.JFrame;
57 import javax.swing.JInternalFrame;
58 import javax.swing.JLabel;
59 import javax.swing.JList;
60 import javax.swing.JPanel;
61 import javax.swing.JScrollPane;
62 import javax.swing.JSeparator;
63 import javax.swing.JTabbedPane;
64 import javax.swing.JTable;
65 import javax.swing.JTextField;
66 import javax.swing.ListCellRenderer;
67 import javax.swing.event.ChangeEvent;
68 import javax.swing.event.ChangeListener;
69 import javax.swing.event.DocumentEvent;
70 import javax.swing.event.DocumentListener;
71 import javax.swing.event.InternalFrameEvent;
72 import javax.swing.table.TableColumn;
73
74 import net.miginfocom.swing.MigLayout;
75
76 @SuppressWarnings("serial")
77 /**
78  * GUI layout for structure chooser
79  * 
80  * @author tcnofoegbu
81  *
82  */
83 public abstract class GStructureChooser extends JPanel
84         implements ItemListener
85 {
86   protected JPanel statusPanel = new JPanel();
87
88   public JLabel statusBar = new JLabel();
89
90   private JPanel pnl_actionsAndStatus = new JPanel(new BorderLayout());
91
92   protected String frameTitle = MessageManager
93           .getString("label.structure_chooser");
94
95   protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
96
97   protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<>();
98
99   protected AlignmentPanel ap;
100
101   protected StringBuilder errorWarning = new StringBuilder();
102
103   protected JLabel lbl_result = new JLabel(
104           MessageManager.getString("label.select"));
105
106   protected JButton btn_view = new JButton();
107
108   protected JButton btn_cancel = new JButton();
109
110   protected JButton btn_pdbFromFile = new JButton();
111
112   protected JTextField txt_search = new JTextField(14);
113
114   private JPanel pnl_actions = new JPanel(new MigLayout());
115
116   private JPanel pnl_main = new JPanel();
117
118   private JPanel pnl_idInput = new JPanel(new FlowLayout());
119
120   private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
121
122   private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
123
124   private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
125
126   private JPanel pnl_locPDB = new JPanel(new BorderLayout());
127
128   protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
129
130   protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
131           .getLayout());
132
133   private BorderLayout mainLayout = new BorderLayout();
134
135   protected JCheckBox chk_rememberSettings = new JCheckBox(
136           MessageManager.getString("label.dont_ask_me_again"));
137
138   protected JCheckBox chk_invertFilter = new JCheckBox(
139           MessageManager.getString("label.invert"));
140
141   protected ImageIcon loadingImage = new ImageIcon(
142           getClass().getResource("/images/loading.gif"));
143
144   protected ImageIcon goodImage = new ImageIcon(
145           getClass().getResource("/images/good.png"));
146
147   protected ImageIcon errorImage = new ImageIcon(
148           getClass().getResource("/images/error.png"));
149
150   protected ImageIcon warningImage = new ImageIcon(
151           getClass().getResource("/images/warning.gif"));
152
153   protected JLabel lbl_warning = new JLabel(warningImage);
154
155   protected JLabel lbl_loading = new JLabel(loadingImage);
156
157   protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
158
159   protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
160
161   protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
162
163   protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
164
165   protected static final String VIEWS_FILTER = "VIEWS_FILTER";
166
167   protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
168
169   protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
170
171   protected JComboBox<StructureViewer> targetView = new JComboBox();
172
173   /**
174    * 'cached' structure view
175    */
176   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
177
178   protected JTable tbl_local_pdb = new JTable();
179
180   protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
181
182   protected JTabbedPane pnl_filter = new JTabbedPane();
183
184   protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
185           PreferenceSource.STRUCTURE_CHOOSER,
186           PDBFTSRestClient.getInstance());
187
188   protected FTSDataColumnI[] previousWantedFields;
189
190   protected static Map<String, Integer> tempUserPrefs = new HashMap<>();
191
192   private JTable tbl_summary = new JTable()
193   {
194     private boolean inLayout;
195
196     @Override
197     public boolean getScrollableTracksViewportWidth()
198     {
199       return hasExcessWidth();
200
201     }
202
203     @Override
204     public void doLayout()
205     {
206       if (hasExcessWidth())
207       {
208         autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
209       }
210       inLayout = true;
211       super.doLayout();
212       inLayout = false;
213       autoResizeMode = AUTO_RESIZE_OFF;
214     }
215
216     protected boolean hasExcessWidth()
217     {
218       return getPreferredSize().width < getParent().getWidth();
219     }
220
221     @Override
222     public void columnMarginChanged(ChangeEvent e)
223     {
224       if (isEditing())
225       {
226         removeEditor();
227       }
228       TableColumn resizingColumn = getTableHeader().getResizingColumn();
229       // Need to do this here, before the parent's
230       // layout manager calls getPreferredSize().
231       if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
232               && !inLayout)
233       {
234         resizingColumn.setPreferredWidth(resizingColumn.getWidth());
235         String colHeader = resizingColumn.getHeaderValue().toString();
236         tempUserPrefs.put(colHeader, resizingColumn.getWidth());
237       }
238       resizeAndRepaint();
239     }
240
241     @Override
242     public String getToolTipText(MouseEvent evt)
243     {
244       String toolTipText = null;
245       java.awt.Point pnt = evt.getPoint();
246       int rowIndex = rowAtPoint(pnt);
247       int colIndex = columnAtPoint(pnt);
248
249       try
250       {
251         if (getValueAt(rowIndex, colIndex) == null)
252         {
253           return null;
254         }
255         toolTipText = getValueAt(rowIndex, colIndex).toString();
256       } catch (Exception e)
257       {
258         // e.printStackTrace();
259       }
260       toolTipText = (toolTipText == null ? null
261               : (toolTipText.length() > 500
262                       ? JvSwingUtils.wrapTooltip(true,
263                               "\"" + toolTipText.subSequence(0, 500)
264                                       + "...\"")
265                       : JvSwingUtils.wrapTooltip(true, toolTipText)));
266       return toolTipText;
267     }
268   };
269
270   protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
271
272   public GStructureChooser()
273   {
274     try
275     {
276       jbInit();
277       mainFrame.setVisible(false);
278       mainFrame.invalidate();
279       mainFrame.pack();
280     } catch (Exception e)
281     {
282       e.printStackTrace();
283     }
284   }
285
286   /**
287    * Initializes the GUI default properties
288    * 
289    * @throws Exception
290    */
291   private void jbInit() throws Exception
292   {
293     Integer width = tempUserPrefs.get("structureChooser.width") == null
294             ? 800
295             : tempUserPrefs.get("structureChooser.width");
296     Integer height = tempUserPrefs.get("structureChooser.height") == null
297             ? 400
298             : tempUserPrefs.get("structureChooser.height");
299     tbl_summary.setAutoCreateRowSorter(true);
300     tbl_summary.getTableHeader().setReorderingAllowed(false);
301     tbl_summary.addMouseListener(new MouseAdapter()
302     {
303       @Override
304       public void mouseClicked(MouseEvent e)
305       {
306         validateSelections();
307       }
308
309       @Override
310       public void mouseReleased(MouseEvent e)
311       {
312         validateSelections();
313       }
314     });
315     tbl_summary.addKeyListener(new KeyAdapter()
316     {
317       @Override
318       public void keyPressed(KeyEvent evt)
319       {
320         validateSelections();
321         switch (evt.getKeyCode())
322         {
323         case KeyEvent.VK_ESCAPE: // escape key
324           mainFrame.dispose();
325           break;
326         case KeyEvent.VK_ENTER: // enter key
327           if (btn_view.isEnabled())
328           {
329             ok_ActionPerformed();
330           }
331           break;
332         case KeyEvent.VK_TAB: // tab key
333           if (evt.isShiftDown())
334           {
335             pnl_filter.requestFocus();
336           }
337           else
338           {
339             btn_view.requestFocus();
340           }
341           evt.consume();
342           break;
343         default:
344           return;
345         }
346       }
347     });
348     tbl_local_pdb.setAutoCreateRowSorter(true);
349     tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
350     tbl_local_pdb.addMouseListener(new MouseAdapter()
351     {
352       @Override
353       public void mouseClicked(MouseEvent e)
354       {
355         validateSelections();
356       }
357
358       @Override
359       public void mouseReleased(MouseEvent e)
360       {
361         validateSelections();
362       }
363     });
364     tbl_local_pdb.addKeyListener(new KeyAdapter()
365     {
366       @Override
367       public void keyPressed(KeyEvent evt)
368       {
369         validateSelections();
370         switch (evt.getKeyCode())
371         {
372         case KeyEvent.VK_ESCAPE: // escape key
373           mainFrame.dispose();
374           break;
375         case KeyEvent.VK_ENTER: // enter key
376           if (btn_view.isEnabled())
377           {
378             ok_ActionPerformed();
379           }
380           break;
381         case KeyEvent.VK_TAB: // tab key
382           if (evt.isShiftDown())
383           {
384             cmb_filterOption.requestFocus();
385           }
386           else
387           {
388             if (btn_view.isEnabled())
389             {
390               btn_view.requestFocus();
391             }
392             else
393             {
394               btn_cancel.requestFocus();
395             }
396           }
397           evt.consume();
398           break;
399         default:
400           return;
401         }
402       }
403     });
404     btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
405     btn_view.setText(MessageManager.getString("action.view"));
406     btn_view.addActionListener(new java.awt.event.ActionListener()
407     {
408       @Override
409       public void actionPerformed(ActionEvent e)
410       {
411         ok_ActionPerformed();
412       }
413     });
414     btn_view.addKeyListener(new KeyAdapter()
415     {
416       @Override
417       public void keyPressed(KeyEvent evt)
418       {
419         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
420         {
421           ok_ActionPerformed();
422         }
423       }
424     });
425
426     btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
427     btn_cancel.setText(MessageManager.getString("action.cancel"));
428     btn_cancel.addActionListener(new java.awt.event.ActionListener()
429     {
430       @Override
431       public void actionPerformed(ActionEvent e)
432       {
433         closeAction(pnl_filter.getHeight());
434       }
435     });
436     btn_cancel.addKeyListener(new KeyAdapter()
437     {
438       @Override
439       public void keyPressed(KeyEvent evt)
440       {
441         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
442         {
443           closeAction(pnl_filter.getHeight());
444         }
445       }
446     });
447
448     btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
449     String btn_title = MessageManager.getString("label.select_pdb_file");
450     btn_pdbFromFile.setText(btn_title + "              ");
451     btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
452     {
453       @Override
454       public void actionPerformed(ActionEvent e)
455       {
456         pdbFromFile_actionPerformed();
457       }
458     });
459     btn_pdbFromFile.addKeyListener(new KeyAdapter()
460     {
461       @Override
462       public void keyPressed(KeyEvent evt)
463       {
464         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
465         {
466           pdbFromFile_actionPerformed();
467         }
468       }
469     });
470
471     scrl_foundStructures.setPreferredSize(new Dimension(width, height));
472
473     scrl_localPDB.setPreferredSize(new Dimension(width, height));
474     scrl_localPDB.setHorizontalScrollBarPolicy(
475             JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
476
477     cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
478     chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
479     chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
480     chk_rememberSettings.setVisible(false);
481     txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
482             MessageManager.getString("label.enter_pdb_id_tip")));
483     cmb_filterOption.setToolTipText(
484             MessageManager.getString("info.select_filter_option"));
485     txt_search.getDocument().addDocumentListener(new DocumentListener()
486     {
487       @Override
488       public void insertUpdate(DocumentEvent e)
489       {
490         txt_search_ActionPerformed();
491       }
492
493       @Override
494       public void removeUpdate(DocumentEvent e)
495       {
496         txt_search_ActionPerformed();
497       }
498
499       @Override
500       public void changedUpdate(DocumentEvent e)
501       {
502         txt_search_ActionPerformed();
503       }
504     });
505
506     cmb_filterOption.addItemListener(this);
507
508     // add CustomComboSeparatorsRenderer to filter option combo-box
509     cmb_filterOption.setRenderer(new CustomComboSeparatorsRenderer(
510             (ListCellRenderer<Object>) cmb_filterOption.getRenderer())
511     {
512       @Override
513       protected boolean addSeparatorAfter(JList list, FilterOption value,
514               int index)
515       {
516         return value.isAddSeparatorAfter();
517       }
518     });
519
520     chk_invertFilter.addItemListener(this);
521
522     targetView.setVisible(false);
523     pnl_actions.add(targetView,"wrap");
524     pnl_actions.add(chk_rememberSettings);
525     pnl_actions.add(btn_view);
526     pnl_actions.add(btn_cancel);
527
528     // pnl_filter.add(lbl_result);
529     pnl_main.add(cmb_filterOption);
530     pnl_main.add(lbl_loading);
531     pnl_main.add(chk_invertFilter);
532     lbl_loading.setVisible(false);
533
534     pnl_fileChooser.add(btn_pdbFromFile);
535     pnl_fileChooser.add(lbl_fromFileStatus);
536     pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
537     pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
538
539     pnl_idInput.add(txt_search);
540     pnl_idInput.add(lbl_pdbManualFetchStatus);
541     pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
542     pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
543
544     final String foundStructureSummary = MessageManager
545             .getString("label.found_structures_summary");
546     final String configureCols = MessageManager
547             .getString("label.configure_displayed_columns");
548     ChangeListener changeListener = new ChangeListener()
549     {
550       @Override
551       public void stateChanged(ChangeEvent changeEvent)
552       {
553         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
554                 .getSource();
555         int index = sourceTabbedPane.getSelectedIndex();
556         btn_view.setVisible(true);
557         btn_cancel.setVisible(true);
558         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
559         {
560           btn_view.setEnabled(false);
561           btn_cancel.setEnabled(false);
562           btn_view.setVisible(false);
563           btn_cancel.setVisible(false);
564           previousWantedFields = pdbDocFieldPrefs
565                   .getStructureSummaryFields()
566                   .toArray(new FTSDataColumnI[0]);
567         }
568         if (sourceTabbedPane.getTitleAt(index)
569                 .equals(foundStructureSummary))
570         {
571           btn_cancel.setEnabled(true);
572           if (wantedFieldsUpdated())
573           {
574             tabRefresh();
575           }
576           else
577           {
578             validateSelections();
579           }
580         }
581       }
582     };
583     pnl_filter.addChangeListener(changeListener);
584     pnl_filter.setPreferredSize(new Dimension(width, height));
585     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
586     pnl_filter.add(configureCols, pdbDocFieldPrefs);
587
588     pnl_locPDB.add(scrl_localPDB);
589
590     pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
591     pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
592     pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
593     pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
594
595     this.setLayout(mainLayout);
596     this.add(pnl_main, java.awt.BorderLayout.NORTH);
597     this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
598     // this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
599     statusPanel.setLayout(new GridLayout());
600     pnl_actionsAndStatus.add(pnl_actions, BorderLayout.CENTER);
601     pnl_actionsAndStatus.add(statusPanel, BorderLayout.SOUTH);
602     statusPanel.add(statusBar, null);
603     this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
604
605     mainFrame.addInternalFrameListener(
606             new javax.swing.event.InternalFrameAdapter()
607             {
608               @Override
609               public void internalFrameClosing(InternalFrameEvent e)
610               {
611                 closeAction(pnl_filter.getHeight());
612               }
613             });
614     mainFrame.setVisible(true);
615     mainFrame.setContentPane(this);
616     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
617     Integer x = tempUserPrefs.get("structureChooser.x");
618     Integer y = tempUserPrefs.get("structureChooser.y");
619     if (x != null && y != null)
620     {
621       mainFrame.setLocation(x, y);
622     }
623     Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
624   }
625
626   protected void closeAction(int preferredHeight)
627   {
628     // System.out.println(">>>>>>>>>> closing internal frame!!!");
629     // System.out.println("width : " + mainFrame.getWidth());
630     // System.out.println("heigh : " + mainFrame.getHeight());
631     // System.out.println("x : " + mainFrame.getX());
632     // System.out.println("y : " + mainFrame.getY());
633     tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
634     tempUserPrefs.put("structureChooser.height", preferredHeight);
635     tempUserPrefs.put("structureChooser.x", mainFrame.getX());
636     tempUserPrefs.put("structureChooser.y", mainFrame.getY());
637     mainFrame.dispose();
638   }
639
640   public boolean wantedFieldsUpdated()
641   {
642     if (previousWantedFields == null)
643     {
644       return true;
645     }
646
647     FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
648             .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
649     return Arrays.equals(currentWantedFields, previousWantedFields) ? false
650             : true;
651
652   }
653
654   @Override
655   /**
656    * Event listener for the 'filter' combo-box and 'invert' check-box
657    */
658   public void itemStateChanged(ItemEvent e)
659   {
660     stateChanged(e);
661   }
662
663   /**
664    * This inner class provides the data model for the structure filter combo-box
665    * 
666    * @author tcnofoegbu
667    *
668    */
669   public class FilterOption
670   {
671     private String name;
672
673     private String value;
674
675     private String view;
676
677     private boolean addSeparatorAfter;
678
679     /**
680      * Model for structure filter option
681      * 
682      * @param name
683      *          - the name of the Option
684      * @param value
685      *          - the value of the option
686      * @param view
687      *          - the category of the filter option
688      * @param addSeparatorAfter
689      *          - if true, a horizontal separator is rendered immediately after
690      *          this filter option, otherwise
691      */
692     public FilterOption(String name, String value, String view,
693             boolean addSeparatorAfter)
694     {
695       this.name = name;
696       this.value = value;
697       this.view = view;
698       this.addSeparatorAfter = addSeparatorAfter;
699     }
700
701     public String getName()
702     {
703       return name;
704     }
705
706     public void setName(String name)
707     {
708       this.name = name;
709     }
710
711     public String getValue()
712     {
713       return value;
714     }
715
716     public void setValue(String value)
717     {
718       this.value = value;
719     }
720
721     public String getView()
722     {
723       return view;
724     }
725
726     public void setView(String view)
727     {
728       this.view = view;
729     }
730
731     @Override
732     public String toString()
733     {
734       return this.name;
735     }
736
737     public boolean isAddSeparatorAfter()
738     {
739       return addSeparatorAfter;
740     }
741
742     public void setAddSeparatorAfter(boolean addSeparatorAfter)
743     {
744       this.addSeparatorAfter = addSeparatorAfter;
745     }
746   }
747
748   /**
749    * This inner class provides the provides the data model for associate
750    * sequence combo-box - cmb_assSeq
751    * 
752    * @author tcnofoegbu
753    *
754    */
755   public class AssociateSeqOptions
756   {
757     private SequenceI sequence;
758
759     private String name;
760
761     public AssociateSeqOptions(SequenceI seq)
762     {
763       this.sequence = seq;
764       this.name = (seq.getName().length() >= 23)
765               ? seq.getName().substring(0, 23)
766               : seq.getName();
767     }
768
769     public AssociateSeqOptions(String name, SequenceI seq)
770     {
771       this.name = name;
772       this.sequence = seq;
773     }
774
775     @Override
776     public String toString()
777     {
778       return name;
779     }
780
781     public String getName()
782     {
783       return name;
784     }
785
786     public void setName(String name)
787     {
788       this.name = name;
789     }
790
791     public SequenceI getSequence()
792     {
793       return sequence;
794     }
795
796     public void setSequence(SequenceI sequence)
797     {
798       this.sequence = sequence;
799     }
800
801   }
802
803   /**
804    * This inner class holds the Layout and configuration of the panel which
805    * handles association of manually fetched structures to a unique sequence
806    * when more than one sequence selection is made
807    * 
808    * @author tcnofoegbu
809    *
810    */
811   public class AssciateSeqPanel extends JPanel implements ItemListener
812   {
813     private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<>();
814
815     private JLabel lbl_associateSeq = new JLabel();
816
817     public AssciateSeqPanel()
818     {
819       this.setLayout(new FlowLayout());
820       this.add(cmb_assSeq);
821       this.add(lbl_associateSeq);
822       cmb_assSeq.setToolTipText(
823               MessageManager.getString("info.associate_wit_sequence"));
824       cmb_assSeq.addItemListener(this);
825     }
826
827     public void loadCmbAssSeq()
828     {
829       populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
830     }
831
832     public JComboBox<AssociateSeqOptions> getCmb_assSeq()
833     {
834       return cmb_assSeq;
835     }
836
837     public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
838     {
839       this.cmb_assSeq = cmb_assSeq;
840     }
841
842     @Override
843     public void itemStateChanged(ItemEvent e)
844     {
845       if (e.getStateChange() == ItemEvent.SELECTED)
846       {
847         cmbAssSeqStateChanged();
848       }
849     }
850   }
851
852   public JTable getResultTable()
853   {
854     return tbl_summary;
855   }
856
857   public JComboBox<FilterOption> getCmbFilterOption()
858   {
859     return cmb_filterOption;
860   }
861
862   /**
863    * Custom ListCellRenderer for adding a separator between different categories
864    * of structure chooser filter option drop-down.
865    * 
866    * @author tcnofoegbu
867    *
868    */
869   public abstract class CustomComboSeparatorsRenderer
870           implements ListCellRenderer<Object>
871   {
872     private ListCellRenderer<Object> regent;
873
874     private JPanel separatorPanel = new JPanel(new BorderLayout());
875
876     private JSeparator jSeparator = new JSeparator();
877
878     public CustomComboSeparatorsRenderer(
879             ListCellRenderer<Object> listCellRenderer)
880     {
881       this.regent = listCellRenderer;
882     }
883
884     @Override
885     public Component getListCellRendererComponent(JList list, Object value,
886             int index, boolean isSelected, boolean cellHasFocus)
887     {
888
889       Component comp = regent.getListCellRendererComponent(list, value,
890               index, isSelected, cellHasFocus);
891       if (index != -1
892               && addSeparatorAfter(list, (FilterOption) value, index))
893       {
894         separatorPanel.removeAll();
895         separatorPanel.add(comp, BorderLayout.CENTER);
896         separatorPanel.add(jSeparator, BorderLayout.SOUTH);
897         return separatorPanel;
898       }
899       else
900       {
901         return comp;
902       }
903     }
904
905     protected abstract boolean addSeparatorAfter(JList list,
906             FilterOption value, int index);
907   }
908
909   protected abstract void stateChanged(ItemEvent e);
910
911   protected abstract void ok_ActionPerformed();
912
913   protected abstract void pdbFromFile_actionPerformed();
914
915   protected abstract void txt_search_ActionPerformed();
916
917   public abstract void populateCmbAssociateSeqOptions(
918           JComboBox<AssociateSeqOptions> cmb_assSeq,
919           JLabel lbl_associateSeq);
920
921   public abstract void cmbAssSeqStateChanged();
922
923   public abstract void tabRefresh();
924
925   public abstract void validateSelections();
926 }