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