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