JAL-1860 house keeping
[jalview.git] / src / jalview / jbgui / GStructureChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21
22 package jalview.jbgui;
23
24 import jalview.datamodel.SequenceI;
25 import jalview.gui.AlignmentPanel;
26 import jalview.gui.Desktop;
27 import jalview.gui.JvSwingUtils;
28 import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource;
29 import jalview.util.MessageManager;
30 import jalview.ws.dbsources.PDBRestClient;
31 import jalview.ws.dbsources.PDBRestClient.PDBDocField;
32
33 import java.awt.BorderLayout;
34 import java.awt.CardLayout;
35 import java.awt.Dimension;
36 import java.awt.FlowLayout;
37 import java.awt.event.ActionEvent;
38 import java.awt.event.ItemEvent;
39 import java.awt.event.ItemListener;
40 import java.awt.event.KeyAdapter;
41 import java.awt.event.KeyEvent;
42 import java.awt.event.MouseAdapter;
43 import java.awt.event.MouseEvent;
44 import java.util.Arrays;
45
46 import javax.swing.ImageIcon;
47 import javax.swing.JButton;
48 import javax.swing.JCheckBox;
49 import javax.swing.JComboBox;
50 import javax.swing.JFrame;
51 import javax.swing.JInternalFrame;
52 import javax.swing.JLabel;
53 import javax.swing.JPanel;
54 import javax.swing.JScrollPane;
55 import javax.swing.JTabbedPane;
56 import javax.swing.JTable;
57 import javax.swing.JTextField;
58 import javax.swing.event.ChangeEvent;
59 import javax.swing.event.ChangeListener;
60 import javax.swing.event.DocumentEvent;
61 import javax.swing.event.DocumentListener;
62
63 @SuppressWarnings("serial")
64 /**
65  * GUI layout for structure chooser 
66  * @author tcnofoegbu
67  *
68  */
69 public abstract class GStructureChooser extends JPanel implements
70         ItemListener
71 {
72   protected String frameTitle = MessageManager
73           .getString("label.structure_chooser");
74
75   protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
76
77   protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<FilterOption>();
78
79   protected AlignmentPanel ap;
80
81   protected StringBuilder errorWarning = new StringBuilder();
82
83   protected JLabel lbl_result = new JLabel(
84           MessageManager.getString("label.select"));
85
86   protected JButton btn_view = new JButton();
87
88   protected JButton btn_cancel = new JButton();
89
90   protected JButton btn_pdbFromFile = new JButton();
91
92   protected JTextField txt_search = new JTextField(14);
93
94   private JPanel pnl_actions = new JPanel();
95
96   private JPanel pnl_main = new JPanel();
97
98   private JPanel pnl_idInput = new JPanel(new FlowLayout());
99
100   private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
101
102   private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
103
104   private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
105
106   private JPanel pnl_locPDB = new JPanel(new BorderLayout());
107
108   protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
109
110   protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
111           .getLayout());
112
113   private BorderLayout mainLayout = new BorderLayout();
114
115   protected JCheckBox chk_rememberSettings = new JCheckBox(
116           MessageManager.getString("label.dont_ask_me_again"));
117
118   protected JCheckBox chk_invertFilter = new JCheckBox(
119           MessageManager.getString("label.invert"));
120
121   protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
122           "/images/loading.gif"));
123
124   protected ImageIcon goodImage = new ImageIcon(getClass().getResource(
125           "/images/good.png"));
126
127   protected ImageIcon errorImage = new ImageIcon(getClass().getResource(
128           "/images/error.png"));
129
130   protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
131           "/images/warning.gif"));
132
133   protected JLabel lbl_warning = new JLabel(warningImage);
134
135   protected JLabel lbl_loading = new JLabel(loadingImage);
136
137   protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
138
139   protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
140
141   protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
142
143   protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
144
145   protected static final String VIEWS_FILTER = "VIEWS_FILTER";
146
147   protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
148
149   protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
150
151   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
152
153   protected JTable tbl_summary = new JTable()
154   {
155     public String getToolTipText(MouseEvent evt)
156     {
157       String toolTipText = null;
158       java.awt.Point pnt = evt.getPoint();
159       int rowIndex = rowAtPoint(pnt);
160       int colIndex = columnAtPoint(pnt);
161
162       try
163       {
164         toolTipText = getValueAt(rowIndex, colIndex).toString();
165       } catch (Exception e)
166       {
167         e.printStackTrace();
168       }
169       toolTipText = (toolTipText == null ? null
170               : (toolTipText.length() > 500 ? JvSwingUtils.wrapTooltip(
171                       true, "\"" + toolTipText.subSequence(0, 500)
172                               + "...\"") : JvSwingUtils.wrapTooltip(true,
173                       toolTipText)));
174       return toolTipText;
175     }
176   };
177
178   protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
179
180   protected JTable tbl_local_pdb = new JTable();
181
182   protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
183
184   private JTabbedPane pnl_filter = new JTabbedPane();
185
186   private PDBDocFieldPreferences pdbDocFieldPrefs = new PDBDocFieldPreferences(
187           PreferenceSource.STRUCTURE_CHOOSER);
188
189   protected PDBDocField[] previousWantedFields;
190
191   public GStructureChooser()
192   {
193     try
194     {
195       jbInit();
196       mainFrame.setVisible(false);
197       mainFrame.invalidate();
198       mainFrame.pack();
199     } catch (Exception e)
200     {
201       e.printStackTrace();
202     }
203   }
204
205   /**
206    * Initializes the GUI default properties
207    * 
208    * @throws Exception
209    */
210   private void jbInit() throws Exception
211   {
212     tbl_summary.setAutoCreateRowSorter(true);
213     tbl_summary.getTableHeader().setReorderingAllowed(false);
214     tbl_summary.addMouseListener(new MouseAdapter()
215     {
216       public void mouseClicked(MouseEvent e)
217       {
218         validateSelections();
219       }
220
221       public void mouseReleased(MouseEvent e)
222       {
223         validateSelections();
224       }
225     });
226     tbl_summary.addKeyListener(new KeyAdapter()
227     {
228       @Override
229       public void keyPressed(KeyEvent evt)
230       {
231         validateSelections();
232         switch (evt.getKeyCode())
233         {
234         case KeyEvent.VK_ESCAPE: // escape key
235           mainFrame.dispose();
236           break;
237         case KeyEvent.VK_ENTER: // enter key
238           if (btn_view.isEnabled())
239           {
240             ok_ActionPerformed();
241           }
242           break;
243         case KeyEvent.VK_TAB: // tab key
244           if (evt.isShiftDown())
245           {
246             pnl_filter.requestFocus();
247           }
248           else
249           {
250             btn_view.requestFocus();
251           }
252           evt.consume();
253           break;
254         default:
255           return;
256         }
257       }
258     });
259     tbl_local_pdb.setAutoCreateRowSorter(true);
260     tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
261     tbl_local_pdb.addMouseListener(new MouseAdapter()
262     {
263       public void mouseClicked(MouseEvent e)
264       {
265         validateSelections();
266       }
267
268       public void mouseReleased(MouseEvent e)
269       {
270         validateSelections();
271       }
272     });
273     tbl_local_pdb.addKeyListener(new KeyAdapter()
274     {
275       @Override
276       public void keyPressed(KeyEvent evt)
277       {
278         validateSelections();
279         switch (evt.getKeyCode())
280         {
281         case KeyEvent.VK_ESCAPE: // escape key
282           mainFrame.dispose();
283           break;
284         case KeyEvent.VK_ENTER: // enter key
285           if (btn_view.isEnabled())
286           {
287             ok_ActionPerformed();
288           }
289           break;
290         case KeyEvent.VK_TAB: // tab key
291           if (evt.isShiftDown())
292           {
293             cmb_filterOption.requestFocus();
294           }
295           else
296           {
297             if (btn_view.isEnabled())
298             {
299             btn_view.requestFocus();
300             }
301             else
302             {
303               btn_cancel.requestFocus();
304             }
305           }
306           evt.consume();
307         default:
308           return;
309         }
310       }
311     });
312     btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
313     btn_view.setText(MessageManager.getString("action.view"));
314     btn_view.addActionListener(new java.awt.event.ActionListener()
315     {
316       public void actionPerformed(ActionEvent e)
317       {
318         ok_ActionPerformed();
319       }
320     });
321     btn_view.addKeyListener(new KeyAdapter()
322     {
323       @Override
324       public void keyPressed(KeyEvent evt)
325       {
326         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
327         {
328           ok_ActionPerformed();
329         }
330       }
331     });
332
333     btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
334     btn_cancel.setText(MessageManager.getString("action.cancel"));
335     btn_cancel.addActionListener(new java.awt.event.ActionListener()
336     {
337       public void actionPerformed(ActionEvent e)
338       {
339         mainFrame.dispose();
340       }
341     });
342     btn_cancel.addKeyListener(new KeyAdapter()
343     {
344       @Override
345       public void keyPressed(KeyEvent evt)
346       {
347         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
348         {
349           mainFrame.dispose();
350         }
351       }
352     });
353
354     btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
355     String btn_title = MessageManager.getString("label.select_pdb_file");
356     btn_pdbFromFile.setText(btn_title + "              ");
357     btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
358     {
359       public void actionPerformed(ActionEvent e)
360       {
361         pdbFromFile_actionPerformed();
362       }
363     });
364     btn_pdbFromFile.addKeyListener(new KeyAdapter()
365     {
366       @Override
367       public void keyPressed(KeyEvent evt)
368       {
369         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
370         {
371           pdbFromFile_actionPerformed();
372         }
373       }
374     });
375
376     scrl_foundStructures.setPreferredSize(new Dimension(500, 300));
377     scrl_foundStructures
378             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
379
380     scrl_localPDB.setPreferredSize(new Dimension(500, 300));
381     scrl_localPDB
382             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
383
384     cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
385     chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
386     chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
387     chk_rememberSettings.setVisible(false);
388
389     txt_search.setToolTipText(MessageManager
390             .getString("label.enter_pdb_id"));
391     cmb_filterOption.setToolTipText(MessageManager
392             .getString("info.select_filter_option"));
393     txt_search.getDocument().addDocumentListener(new DocumentListener()
394     {
395       @Override
396       public void insertUpdate(DocumentEvent e)
397       {
398         txt_search_ActionPerformed();
399       }
400
401       @Override
402       public void removeUpdate(DocumentEvent e)
403       {
404         txt_search_ActionPerformed();
405       }
406
407       @Override
408       public void changedUpdate(DocumentEvent e)
409       {
410         txt_search_ActionPerformed();
411       }
412     });
413
414     cmb_filterOption.addItemListener(this);
415     chk_invertFilter.addItemListener(this);
416
417     pnl_actions.add(chk_rememberSettings);
418     pnl_actions.add(btn_view);
419     pnl_actions.add(btn_cancel);
420
421     // pnl_filter.add(lbl_result);
422     pnl_main.add(cmb_filterOption);
423     pnl_main.add(lbl_loading);
424     pnl_main.add(chk_invertFilter);
425     lbl_loading.setVisible(false);
426
427     pnl_fileChooser.add(btn_pdbFromFile);
428     pnl_fileChooser.add(lbl_fromFileStatus);
429     pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
430     pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
431
432     pnl_idInput.add(txt_search);
433     pnl_idInput.add(lbl_pdbManualFetchStatus);
434     pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
435     pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
436
437     final String foundStructureSummary = MessageManager
438             .getString("label.found_structures_summary");
439     final String configureCols = MessageManager
440             .getString("label.configure_displayed_columns");
441     ChangeListener changeListener = new ChangeListener()
442     {
443       public void stateChanged(ChangeEvent changeEvent)
444       {
445         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
446                 .getSource();
447         int index = sourceTabbedPane.getSelectedIndex();
448         if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
449         {
450           btn_view.setEnabled(false);
451           btn_cancel.setEnabled(false);
452           previousWantedFields = PDBDocFieldPreferences
453                   .getStructureSummaryFields().toArray(
454                           new PDBRestClient.PDBDocField[0]);
455         }
456         if (sourceTabbedPane.getTitleAt(index)
457                 .equals(foundStructureSummary))
458         {
459           btn_cancel.setEnabled(true);
460           if (wantedFieldsUpdated())
461           {
462             tabRefresh();
463           }
464           else
465           {
466             validateSelections();
467           }
468         }
469       }
470     };
471     pnl_filter.addChangeListener(changeListener);
472     pnl_filter.setPreferredSize(new Dimension(500, 300));
473     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
474     pnl_filter.add(configureCols, pdbDocFieldPrefs);
475
476     pnl_locPDB.add(scrl_localPDB);
477
478     pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
479     pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
480     pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
481     pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
482
483     this.setLayout(mainLayout);
484     this.add(pnl_main, java.awt.BorderLayout.NORTH);
485     this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
486     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
487
488     mainFrame.setVisible(true);
489     mainFrame.setContentPane(this);
490     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
491     Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400);
492   }
493
494   public boolean wantedFieldsUpdated()
495   {
496     if (previousWantedFields == null)
497     {
498       return true;
499     }
500
501     return Arrays.equals(PDBDocFieldPreferences.getStructureSummaryFields()
502             .toArray(new PDBRestClient.PDBDocField[0]),
503             previousWantedFields) ? false : true;
504
505   }
506
507   @Override
508   /**
509    * Event listener for the 'filter' combo-box and 'invert' check-box
510    */
511   public void itemStateChanged(ItemEvent e)
512   {
513     stateChanged(e);
514   }
515
516   /**
517    * This inner class provides the data model for the structure filter combo-box
518    * 
519    * @author tcnofoegbu
520    *
521    */
522   public class FilterOption
523   {
524     private String name;
525
526     private String value;
527
528     private String view;
529
530     public FilterOption(String name, String value, String view)
531     {
532       this.name = name;
533       this.value = value;
534       this.view = view;
535     }
536
537     public String getName()
538     {
539       return name;
540     }
541
542     public void setName(String name)
543     {
544       this.name = name;
545     }
546
547     public String getValue()
548     {
549       return value;
550     }
551
552     public void setValue(String value)
553     {
554       this.value = value;
555     }
556
557     public String getView()
558     {
559       return view;
560     }
561
562     public void setView(String view)
563     {
564       this.view = view;
565     }
566
567     public String toString()
568     {
569       return this.name;
570     }
571   }
572
573   /**
574    * This inner class provides the provides the data model for associate
575    * sequence combo-box - cmb_assSeq
576    * 
577    * @author tcnofoegbu
578    *
579    */
580   public class AssociateSeqOptions
581   {
582     private SequenceI sequence;
583
584     private String name;
585
586     public AssociateSeqOptions(SequenceI seq)
587     {
588       this.sequence = seq;
589       this.name = (seq.getName().length() >= 23) ? seq.getName().substring(
590               0, 23) : seq.getName();
591     }
592
593     public AssociateSeqOptions(String name, SequenceI seq)
594     {
595       this.name = name;
596       this.sequence = seq;
597     }
598
599     public String toString()
600     {
601       return name;
602     }
603
604     public String getName()
605     {
606       return name;
607     }
608
609     public void setName(String name)
610     {
611       this.name = name;
612     }
613
614     public SequenceI getSequence()
615     {
616       return sequence;
617     }
618
619     public void setSequence(SequenceI sequence)
620     {
621       this.sequence = sequence;
622     }
623
624   }
625
626   /**
627    * This inner class holds the Layout and configuration of the panel which
628    * handles association of manually fetched structures to a unique sequence
629    * when more than one sequence selection is made
630    * 
631    * @author tcnofoegbu
632    *
633    */
634   public class AssciateSeqPanel extends JPanel implements ItemListener
635   {
636     private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<AssociateSeqOptions>();
637
638     private JLabel lbl_associateSeq = new JLabel();
639
640     public AssciateSeqPanel()
641     {
642       this.setLayout(new FlowLayout());
643       this.add(cmb_assSeq);
644       this.add(lbl_associateSeq);
645       cmb_assSeq.setToolTipText(MessageManager
646               .getString("info.associate_wit_sequence"));
647       cmb_assSeq.addItemListener(this);
648     }
649
650     public void loadCmbAssSeq()
651     {
652       populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
653     }
654
655     public JComboBox<AssociateSeqOptions> getCmb_assSeq()
656     {
657       return cmb_assSeq;
658     }
659
660     public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
661     {
662       this.cmb_assSeq = cmb_assSeq;
663     }
664
665     @Override
666     public void itemStateChanged(ItemEvent e)
667     {
668       if (e.getStateChange() == ItemEvent.SELECTED)
669       {
670         cmbAssSeqStateChanged();
671       }
672     }
673   }
674
675   public JComboBox<FilterOption> getCmbFilterOption()
676   {
677     return cmb_filterOption;
678   }
679
680   protected abstract void stateChanged(ItemEvent e);
681
682   protected abstract void updateCurrentView();
683
684   protected abstract void populateFilterComboBox();
685
686   protected abstract void ok_ActionPerformed();
687
688   protected abstract void pdbFromFile_actionPerformed();
689
690   protected abstract void txt_search_ActionPerformed();
691
692   public abstract void populateCmbAssociateSeqOptions(
693           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq);
694
695   public abstract void cmbAssSeqStateChanged();
696
697   public abstract void tabRefresh();
698
699   public abstract void validateSelections();
700 }