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