JAL-1834 disabled action buttons (Back / Ok / Cancel) when in 'Configure Displayed...
[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.MouseAdapter;
41 import java.awt.event.MouseEvent;
42 import java.util.Arrays;
43
44 import javax.swing.ImageIcon;
45 import javax.swing.JButton;
46 import javax.swing.JCheckBox;
47 import javax.swing.JComboBox;
48 import javax.swing.JFrame;
49 import javax.swing.JInternalFrame;
50 import javax.swing.JLabel;
51 import javax.swing.JPanel;
52 import javax.swing.JScrollPane;
53 import javax.swing.JTabbedPane;
54 import javax.swing.JTable;
55 import javax.swing.JTextField;
56 import javax.swing.event.ChangeEvent;
57 import javax.swing.event.ChangeListener;
58 import javax.swing.event.DocumentEvent;
59 import javax.swing.event.DocumentListener;
60
61 @SuppressWarnings("serial")
62 /**
63  * GUI layout for structure chooser 
64  * @author tcnofoegbu
65  *
66  */
67 public abstract class GStructureChooser extends JPanel implements
68         ItemListener
69 {
70   protected String frameTitle = MessageManager
71           .getString("label.structure_chooser");
72
73   protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
74
75   protected JComboBox<FilterOption> cmb_filterOption = new JComboBox<FilterOption>();
76
77   protected AlignmentPanel ap;
78   
79   protected StringBuilder errorWarning = new StringBuilder();
80
81   protected JLabel lbl_result = new JLabel(
82           MessageManager.getString("label.select"));
83
84   protected JButton btn_view = new JButton();
85
86   protected JButton btn_cancel = new JButton();
87
88   protected JButton btn_pdbFromFile = new JButton();
89
90   protected JTextField txt_search = new JTextField(14);
91
92   private JPanel pnl_actions = new JPanel();
93
94   private JPanel pnl_main = new JPanel();
95
96   private JPanel pnl_idInput = new JPanel(new FlowLayout());
97
98   private JPanel pnl_fileChooser = new JPanel(new FlowLayout());
99
100   private JPanel pnl_idInputBL = new JPanel(new BorderLayout());
101
102   private JPanel pnl_fileChooserBL = new JPanel(new BorderLayout());
103
104   private JPanel pnl_locPDB = new JPanel(new BorderLayout());
105
106   protected JPanel pnl_switchableViews = new JPanel(new CardLayout());
107
108   protected CardLayout layout_switchableViews = (CardLayout) (pnl_switchableViews
109           .getLayout());
110
111   private BorderLayout mainLayout = new BorderLayout();
112
113   protected JCheckBox chk_rememberSettings = new JCheckBox(
114           MessageManager.getString("label.dont_ask_me_again"));
115
116   protected JCheckBox chk_invertFilter = new JCheckBox(
117           MessageManager.getString("label.invert"));
118
119   protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
120           "/images/loading.gif"));
121
122   protected ImageIcon goodImage = new ImageIcon(getClass().getResource(
123           "/images/good.png"));
124
125   protected ImageIcon errorImage = new ImageIcon(getClass().getResource(
126           "/images/error.png"));
127
128   protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
129           "/images/warning.gif"));
130
131   protected JLabel lbl_warning = new JLabel(warningImage);
132
133   protected JLabel lbl_loading = new JLabel(loadingImage);
134
135   protected JLabel lbl_pdbManualFetchStatus = new JLabel(errorImage);
136
137   protected JLabel lbl_fromFileStatus = new JLabel(errorImage);
138
139
140   protected AssciateSeqPanel idInputAssSeqPanel = new AssciateSeqPanel();
141
142   protected AssciateSeqPanel fileChooserAssSeqPanel = new AssciateSeqPanel();
143
144   protected static final String VIEWS_FILTER = "VIEWS_FILTER";
145
146   protected static final String VIEWS_FROM_FILE = "VIEWS_FROM_FILE";
147
148   protected static final String VIEWS_ENTER_ID = "VIEWS_ENTER_ID";
149
150   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
151
152   protected JTable tbl_summary = new JTable()
153   {
154     public String getToolTipText(MouseEvent evt)
155     {
156       String toolTipText = null;
157       java.awt.Point pnt = evt.getPoint();
158       int rowIndex = rowAtPoint(pnt);
159       int colIndex = columnAtPoint(pnt);
160
161       try
162       {
163         toolTipText = getValueAt(rowIndex, colIndex).toString();
164       } catch (Exception e)
165       {
166         e.printStackTrace();
167       }
168       toolTipText = (toolTipText == null ? null : JvSwingUtils.wrapTooltip(
169               true, toolTipText));
170       return toolTipText;
171     }
172   };
173
174   protected JScrollPane scrl_foundStructures = new JScrollPane(
175           tbl_summary);
176
177   protected JTable tbl_local_pdb = new JTable();
178
179   protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
180
181   private JTabbedPane pnl_filter = new JTabbedPane();
182
183   private PDBDocFieldPreferences pdbDocFieldPrefs = new PDBDocFieldPreferences(
184           PreferenceSource.STRUCTURE_CHOOSER);
185
186   protected PDBDocField[] previousWantedFields;
187   public GStructureChooser()
188   {
189     try
190     {
191       jbInit();
192       mainFrame.setVisible(false);
193       mainFrame.invalidate();
194       mainFrame.pack();
195     } catch (Exception e)
196     {
197       e.printStackTrace();
198     }
199   }
200
201   /**
202    * Initializes the GUI default properties
203    * 
204    * @throws Exception
205    */
206   private void jbInit() throws Exception
207   {
208     tbl_summary.setAutoCreateRowSorter(true);
209     tbl_summary.getTableHeader().setReorderingAllowed(false);
210     tbl_local_pdb.setAutoCreateRowSorter(true);
211     tbl_local_pdb.getTableHeader().setReorderingAllowed(false);
212     tbl_local_pdb.addMouseListener(new MouseAdapter()
213     {
214       public void mouseClicked(MouseEvent e)
215       {
216         updateCurrentView();
217       }
218
219       public void mouseReleased(MouseEvent e)
220       {
221         updateCurrentView();
222       }
223     });
224
225     btn_view.setFont(new java.awt.Font("Verdana", 0, 12));
226     btn_view.setText(MessageManager.getString("action.view"));
227     btn_view.addActionListener(new java.awt.event.ActionListener()
228     {
229       public void actionPerformed(ActionEvent e)
230       {
231         ok_ActionPerformed();
232       }
233     });
234     btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
235     btn_cancel.setText(MessageManager.getString("action.cancel"));
236     btn_cancel.addActionListener(new java.awt.event.ActionListener()
237     {
238       public void actionPerformed(ActionEvent e)
239       {
240         mainFrame.dispose();
241       }
242     });
243
244     btn_pdbFromFile.setFont(new java.awt.Font("Verdana", 0, 12));
245     String btn_title = MessageManager.getString("label.select_pdb_file");
246     btn_pdbFromFile.setText(btn_title + "              ");
247     btn_pdbFromFile.addActionListener(new java.awt.event.ActionListener()
248     {
249       public void actionPerformed(ActionEvent e)
250       {
251         pdbFromFile_actionPerformed();
252       }
253     });
254
255     scrl_foundStructures.setPreferredSize(new Dimension(500, 300));
256     scrl_foundStructures
257             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
258
259     scrl_localPDB.setPreferredSize(new Dimension(500, 300));
260     scrl_localPDB
261             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
262
263     cmb_filterOption.setFont(new java.awt.Font("Verdana", 0, 12));
264     chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
265     chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
266     chk_rememberSettings.setVisible(false);
267
268     txt_search.setToolTipText(MessageManager
269             .getString("label.enter_pdb_id"));
270     cmb_filterOption.setToolTipText(MessageManager
271             .getString("info.select_filter_option"));
272     txt_search.getDocument().addDocumentListener(new DocumentListener()
273     {
274       @Override
275       public void insertUpdate(DocumentEvent e)
276       {
277         txt_search_ActionPerformed();
278       }
279
280       @Override
281       public void removeUpdate(DocumentEvent e)
282       {
283         txt_search_ActionPerformed();
284       }
285
286       @Override
287       public void changedUpdate(DocumentEvent e)
288       {
289         txt_search_ActionPerformed();
290       }
291     });
292
293     cmb_filterOption.addItemListener(this);
294     chk_invertFilter.addItemListener(this);
295
296     pnl_actions.add(chk_rememberSettings);
297     pnl_actions.add(btn_view);
298     pnl_actions.add(btn_cancel);
299
300     // pnl_filter.add(lbl_result);
301     pnl_main.add(cmb_filterOption);
302     pnl_main.add(lbl_loading);
303     pnl_main.add(chk_invertFilter);
304     lbl_loading.setVisible(false);
305
306
307     pnl_fileChooser.add(btn_pdbFromFile);
308     pnl_fileChooser.add(lbl_fromFileStatus);
309     pnl_fileChooserBL.add(fileChooserAssSeqPanel, BorderLayout.NORTH);
310     pnl_fileChooserBL.add(pnl_fileChooser, BorderLayout.CENTER);
311
312     pnl_idInput.add(txt_search);
313     pnl_idInput.add(lbl_pdbManualFetchStatus);
314     pnl_idInputBL.add(idInputAssSeqPanel, BorderLayout.NORTH);
315     pnl_idInputBL.add(pnl_idInput, BorderLayout.CENTER);
316     
317     final String foundStructureSummary = MessageManager
318             .getString("label.found_structures_summary");
319     final String configureCols = MessageManager
320             .getString("label.configure_displayed_columns");
321     ChangeListener changeListener = new ChangeListener()
322     {
323       public void stateChanged(ChangeEvent changeEvent)
324       {
325         JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
326                 .getSource();
327         int index = sourceTabbedPane.getSelectedIndex();
328         if (sourceTabbedPane.getTitleAt(index)
329 .equals(configureCols))
330         {
331           btn_view.setEnabled(false);
332           btn_cancel.setEnabled(false);
333           previousWantedFields = PDBDocFieldPreferences
334                   .getStructureSummaryFields().toArray(
335                           new PDBRestClient.PDBDocField[0]);
336         }
337         if (sourceTabbedPane.getTitleAt(index)
338                 .equals(foundStructureSummary))
339         {
340           btn_cancel.setEnabled(true);
341           if (wantedFieldsUpdated())
342           {
343             tabRefresh();
344           }
345           else
346           {
347             validateSelections();
348           }
349         }
350       }
351     };
352     pnl_filter.addChangeListener(changeListener);
353     pnl_filter.setPreferredSize(new Dimension(500, 300));
354     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
355     pnl_filter.add(configureCols, pdbDocFieldPrefs);
356     
357     pnl_locPDB.add(scrl_localPDB);
358
359     pnl_switchableViews.add(pnl_fileChooserBL, VIEWS_FROM_FILE);
360     pnl_switchableViews.add(pnl_idInputBL, VIEWS_ENTER_ID);
361     pnl_switchableViews.add(pnl_filter, VIEWS_FILTER);
362     pnl_switchableViews.add(pnl_locPDB, VIEWS_LOCAL_PDB);
363     
364     this.setLayout(mainLayout);
365     this.add(pnl_main, java.awt.BorderLayout.NORTH);
366     this.add(pnl_switchableViews, java.awt.BorderLayout.CENTER);
367     this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
368
369     mainFrame.setVisible(true);
370     mainFrame.setContentPane(this);
371     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
372     Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400);
373   }
374
375   public boolean wantedFieldsUpdated()
376   {
377     if (previousWantedFields == null)
378     {
379       return true;
380     }
381
382     return Arrays.equals(PDBDocFieldPreferences.getStructureSummaryFields()
383             .toArray(new PDBRestClient.PDBDocField[0]),
384             previousWantedFields) ? false : true;
385
386   }
387   
388   @Override
389   /**
390    * Event listener for the 'filter' combo-box and 'invert' check-box
391    */
392   public void itemStateChanged(ItemEvent e)
393   {
394     stateChanged(e);
395   }
396
397   /**
398    * This inner class provides the data model for the structure filter combo-box
399    * 
400    * @author tcnofoegbu
401    *
402    */
403   public class FilterOption
404   {
405     private String name;
406
407     private String value;
408
409     private String view;
410
411     public FilterOption(String name, String value, String view)
412     {
413       this.name = name;
414       this.value = value;
415       this.view = view;
416     }
417
418     public String getName()
419     {
420       return name;
421     }
422
423     public void setName(String name)
424     {
425       this.name = name;
426     }
427
428     public String getValue()
429     {
430       return value;
431     }
432
433     public void setValue(String value)
434     {
435       this.value = value;
436     }
437
438     public String getView()
439     {
440       return view;
441     }
442
443     public void setView(String view)
444     {
445       this.view = view;
446     }
447
448     public String toString()
449     {
450       return this.name;
451     }
452   }
453
454   /**
455    * This inner class provides the provides the data model for associate
456    * sequence combo-box - cmb_assSeq
457    * 
458    * @author tcnofoegbu
459    *
460    */
461   public class AssociateSeqOptions
462   {
463     private SequenceI sequence;
464     private String name;
465
466     public AssociateSeqOptions(SequenceI seq)
467     {
468       this.sequence = seq;
469       this.name = (seq.getName().length() >= 23) ? seq.getName().substring(
470               0, 23) : seq.getName();
471     }
472
473     public AssociateSeqOptions(String name, SequenceI seq)
474     {
475       this.name = name;
476       this.sequence = seq;
477     }
478
479     public String toString()
480     {
481       return name;
482     }
483
484     public String getName()
485     {
486       return name;
487     }
488
489     public void setName(String name)
490     {
491       this.name = name;
492     }
493
494     public SequenceI getSequence()
495     {
496       return sequence;
497     }
498
499     public void setSequence(SequenceI sequence)
500     {
501       this.sequence = sequence;
502     }
503
504   }
505
506   /**
507    * This inner class holds the Layout and configuration of the panel which
508    * handles association of manually fetched structures to a unique sequence
509    * when more than one sequence selection is made
510    * 
511    * @author tcnofoegbu
512    *
513    */
514   public class AssciateSeqPanel extends JPanel implements ItemListener
515   {
516     private JComboBox<AssociateSeqOptions> cmb_assSeq = new JComboBox<AssociateSeqOptions>();
517
518     private JLabel lbl_associateSeq = new JLabel();
519
520     public AssciateSeqPanel()
521     {
522       this.setLayout(new FlowLayout());
523       this.add(cmb_assSeq);
524       this.add(lbl_associateSeq);
525       cmb_assSeq.setToolTipText(MessageManager
526               .getString("info.associate_wit_sequence"));
527       cmb_assSeq.addItemListener(this);
528     }
529
530     public void loadCmbAssSeq()
531     {
532       populateCmbAssociateSeqOptions(cmb_assSeq, lbl_associateSeq);
533     }
534
535     public JComboBox<AssociateSeqOptions> getCmb_assSeq()
536     {
537       return cmb_assSeq;
538     }
539
540     public void setCmb_assSeq(JComboBox<AssociateSeqOptions> cmb_assSeq)
541     {
542       this.cmb_assSeq = cmb_assSeq;
543     }
544
545     @Override
546     public void itemStateChanged(ItemEvent e)
547     {
548       if (e.getStateChange() == ItemEvent.SELECTED)
549       {
550         cmbAssSeqStateChanged();
551       }
552     }
553   }
554
555   public JComboBox<FilterOption> getCmbFilterOption()
556   {
557     return cmb_filterOption;
558   }
559
560   protected abstract void stateChanged(ItemEvent e);
561
562   protected abstract void updateCurrentView();
563
564   protected abstract void populateFilterComboBox();
565
566   protected abstract void ok_ActionPerformed();
567
568   protected abstract void pdbFromFile_actionPerformed();
569
570   protected abstract void txt_search_ActionPerformed();
571
572   public abstract void populateCmbAssociateSeqOptions(
573           JComboBox<AssociateSeqOptions> cmb_assSeq, JLabel lbl_associateSeq);
574
575   public abstract void cmbAssSeqStateChanged();
576
577   public abstract void tabRefresh();
578
579   public abstract void validateSelections();
580 }