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