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