JAL-4046 JAL-3993 patch for 2.11.2.4 release
[jalview.git] / src / jalview / gui / SliderPanel.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 package jalview.gui;
22
23 import jalview.analysis.Conservation;
24 import jalview.datamodel.SequenceGroup;
25 import jalview.jbgui.GSliderPanel;
26 import jalview.renderer.ResidueShaderI;
27 import jalview.util.MessageManager;
28
29 import java.awt.event.ActionEvent;
30 import java.awt.event.MouseAdapter;
31 import java.awt.event.MouseEvent;
32 import java.beans.PropertyVetoException;
33 import java.util.List;
34
35 import javax.swing.JInternalFrame;
36 import javax.swing.JLayeredPane;
37 import javax.swing.event.ChangeEvent;
38 import javax.swing.event.ChangeListener;
39 import javax.swing.event.InternalFrameAdapter;
40 import javax.swing.event.InternalFrameEvent;
41
42 /**
43  * DOCUMENT ME!
44  * 
45  * @author $author$
46  * @version $Revision$
47  */
48 public class SliderPanel extends GSliderPanel
49 {
50   private static final String BACKGROUND = "Background";
51
52   static JInternalFrame conservationSlider;
53
54   static JInternalFrame PIDSlider;
55
56   AlignmentPanel ap;
57
58   boolean forConservation = true;
59
60   ResidueShaderI cs;
61
62   /**
63    * Returns the currently displayed slider panel (or null if none).
64    * 
65    * @return
66    */
67   public static SliderPanel getSliderPanel()
68   {
69     if (conservationSlider != null && conservationSlider.isVisible())
70     {
71       return (SliderPanel) conservationSlider.getContentPane();
72     }
73     if (PIDSlider != null && PIDSlider.isVisible())
74     {
75       return (SliderPanel) PIDSlider.getContentPane();
76     }
77     return null;
78   }
79
80   /**
81    * Creates a new SliderPanel object.
82    * 
83    * @param ap
84    *          DOCUMENT ME!
85    * @param value
86    *          DOCUMENT ME!
87    * @param forConserve
88    *          DOCUMENT ME!
89    * @param scheme
90    *          DOCUMENT ME!
91    */
92   public SliderPanel(final AlignmentPanel ap, int value,
93           boolean forConserve, ResidueShaderI scheme)
94   {
95     this.ap = ap;
96     this.cs = scheme;
97     forConservation = forConserve;
98     undoButton.setVisible(false);
99     applyButton.setVisible(false);
100
101     if (forConservation)
102     {
103       label.setText(MessageManager.getString(
104               "label.enter_value_increase_conservation_visibility"));
105       slider.setMinimum(0);
106       slider.setMaximum(100);
107     }
108     else
109     {
110       label.setText(MessageManager.getString(
111               "label.enter_percentage_identity_above_which_colour_residues"));
112       slider.setMinimum(0);
113       slider.setMaximum(100);
114     }
115
116     slider.addChangeListener(new ChangeListener()
117     {
118       @Override
119       public void stateChanged(ChangeEvent evt)
120       {
121         valueField.setText(String.valueOf(slider.getValue()));
122         valueChanged(slider.getValue());
123       }
124     });
125
126     slider.addMouseListener(new MouseAdapter()
127     {
128       @Override
129       public void mouseReleased(MouseEvent evt)
130       {
131         ap.paintAlignment(true, true);
132       }
133     });
134
135     slider.setValue(value);
136     valueField.setText(String.valueOf(value));
137   }
138
139   /**
140    * Method to 'set focus' of the Conservation slider panel
141    * 
142    * @param ap
143    *          the panel to repaint on change of slider
144    * @param rs
145    *          the colour scheme to update on change of slider
146    * @param source
147    *          a text description for the panel's title
148    * 
149    * @return
150    */
151   public static int setConservationSlider(AlignmentPanel ap,
152           ResidueShaderI rs, String source)
153   {
154     SliderPanel sliderPanel = null;
155
156     if (conservationSlider == null)
157     {
158       sliderPanel = new SliderPanel(ap, rs.getConservationInc(), true, rs);
159       conservationSlider = new JInternalFrame();
160       conservationSlider.setContentPane(sliderPanel);
161       conservationSlider.setLayer(JLayeredPane.PALETTE_LAYER);
162     }
163     else
164     {
165       sliderPanel = (SliderPanel) conservationSlider.getContentPane();
166       sliderPanel.valueField
167               .setText(String.valueOf(rs.getConservationInc()));
168       sliderPanel.cs = rs;
169       sliderPanel.ap = ap;
170       sliderPanel.slider.setValue(rs.getConservationInc());
171     }
172
173     conservationSlider.setTitle(MessageManager.formatMessage(
174             "label.conservation_colour_increment", new String[]
175             { source == null ? BACKGROUND : source }));
176
177     List<SequenceGroup> groups = ap.av.getAlignment().getGroups();
178     if (groups != null && !groups.isEmpty())
179     {
180       sliderPanel.setAllGroupsCheckEnabled(true);
181       sliderPanel.allGroupsCheck
182               .setSelected(ap.av.getColourAppliesToAllGroups());
183     }
184     else
185     {
186       sliderPanel.setAllGroupsCheckEnabled(false);
187     }
188
189     return sliderPanel.getValue();
190   }
191
192   /**
193    * Hides the PID slider panel if it is shown
194    */
195   public static void hidePIDSlider()
196   {
197     if (PIDSlider != null)
198     {
199       try
200       {
201         PIDSlider.setClosed(true);
202         PIDSlider = null;
203       } catch (PropertyVetoException ex)
204       {
205       }
206     }
207   }
208
209   /**
210    * Hides the conservation slider panel if it is shown
211    */
212   public static void hideConservationSlider()
213   {
214     if (conservationSlider != null)
215     {
216       try
217       {
218         conservationSlider.setClosed(true);
219         conservationSlider = null;
220       } catch (PropertyVetoException ex)
221       {
222       }
223     }
224   }
225
226   /**
227    * DOCUMENT ME!
228    */
229   public static void showConservationSlider()
230   {
231     hidePIDSlider();
232
233     if (!conservationSlider.isVisible())
234     {
235       Desktop.addInternalFrame(conservationSlider,
236               conservationSlider.getTitle(), true, FRAME_WIDTH,
237               FRAME_HEIGHT, false, true);
238       conservationSlider.addInternalFrameListener(new InternalFrameAdapter()
239       {
240         @Override
241         public void internalFrameClosed(InternalFrameEvent e)
242         {
243           conservationSlider = null;
244         }
245       });
246       conservationSlider.setLayer(JLayeredPane.PALETTE_LAYER);
247     }
248   }
249
250   /**
251    * Method to 'set focus' of the PID slider panel
252    * 
253    * @param ap
254    *          the panel to repaint on change of slider
255    * @param rs
256    *          the colour scheme to update on change of slider
257    * @param source
258    *          a text description for the panel's title
259    * 
260    * @return
261    */
262   public static int setPIDSliderSource(AlignmentPanel ap, ResidueShaderI rs,
263           String source)
264   {
265     int threshold = rs.getThreshold();
266
267     SliderPanel sliderPanel = null;
268
269     if (PIDSlider == null)
270     {
271       sliderPanel = new SliderPanel(ap, threshold, false, rs);
272       PIDSlider = new JInternalFrame();
273       PIDSlider.setContentPane(sliderPanel);
274       PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER);
275     }
276     else
277     {
278       sliderPanel = (SliderPanel) PIDSlider.getContentPane();
279       sliderPanel.cs = rs;
280       sliderPanel.ap = ap;
281       sliderPanel.valueField.setText(String.valueOf(rs.getThreshold()));
282       sliderPanel.slider.setValue(rs.getThreshold());
283     }
284
285     PIDSlider.setTitle(MessageManager.formatMessage(
286             "label.percentage_identity_threshold", new String[]
287             { source == null ? BACKGROUND : source }));
288
289     if (ap.av.getAlignment().getGroups() != null)
290     {
291       sliderPanel.setAllGroupsCheckEnabled(true);
292     }
293     else
294     {
295       sliderPanel.setAllGroupsCheckEnabled(false);
296     }
297
298     return sliderPanel.getValue();
299   }
300
301   /**
302    * DOCUMENT ME!
303    * 
304    * @return
305    */
306   public static JInternalFrame showPIDSlider()
307   {
308     hideConservationSlider();
309
310     if (!PIDSlider.isVisible())
311     {
312       Desktop.addInternalFrame(PIDSlider, PIDSlider.getTitle(), true,
313               FRAME_WIDTH, FRAME_HEIGHT, false, true);
314       PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER);
315       PIDSlider.addInternalFrameListener(new InternalFrameAdapter()
316       {
317         @Override
318         public void internalFrameClosed(InternalFrameEvent e)
319         {
320           PIDSlider = null;
321         }
322       });
323       PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER);
324     }
325     return PIDSlider;
326   }
327
328   /**
329    * Updates the colour scheme with the current (identity threshold or
330    * conservation) percentage value. Also updates all groups if 'apply to all
331    * groups' is selected.
332    * 
333    * @param percent
334    */
335   public void valueChanged(int percent)
336   {
337     if (!forConservation)
338     {
339       ap.av.setThreshold(percent);
340     }
341     updateColourScheme(percent, cs, null);
342
343     if (allGroupsCheck.isSelected())
344     {
345       List<SequenceGroup> groups = ap.av.getAlignment().getGroups();
346       for (SequenceGroup sg : groups)
347       {
348         updateColourScheme(percent, sg.getGroupColourScheme(), sg);
349       }
350     }
351
352     ap.getSeqPanel().seqCanvas.repaint();
353   }
354
355   /**
356    * Updates the colour scheme (if not null) with the current (identity
357    * threshold or conservation) percentage value
358    * 
359    * @param percent
360    * @param scheme
361    * @param sg
362    */
363   protected void updateColourScheme(int percent, ResidueShaderI scheme,
364           SequenceGroup sg)
365   {
366     if (scheme == null)
367     {
368       return;
369     }
370     if (forConservation)
371     {
372       if (!scheme.conservationApplied() && sg != null)
373       {
374         /*
375          * first time the colour scheme has had Conservation shading applied
376          * - compute conservation
377          */
378         Conservation c = new Conservation("Group", sg.getSequences(null),
379                 sg.getStartRes(), sg.getEndRes());
380         c.calculate();
381         c.verdict(false, ap.av.getConsPercGaps());
382         sg.cs.setConservation(c);
383
384       }
385       scheme.setConservationApplied(true);
386       scheme.setConservationInc(percent);
387     }
388     else
389     {
390       scheme.setThreshold(percent, ap.av.isIgnoreGapsConsensus());
391     }
392   }
393
394   /**
395    * DOCUMENT ME!
396    * 
397    * @param b
398    *          DOCUMENT ME!
399    */
400   public void setAllGroupsCheckEnabled(boolean b)
401   {
402     allGroupsCheck.setEnabled(b);
403   }
404
405   /**
406    * DOCUMENT ME!
407    * 
408    * @param e
409    *          DOCUMENT ME!
410    */
411   @Override
412   public void valueField_actionPerformed()
413   {
414     try
415     {
416       int i = Integer.parseInt(valueField.getText());
417       slider.setValue(i);
418     } catch (NumberFormatException ex)
419     {
420       valueField.setText(slider.getValue() + "");
421     }
422   }
423
424   /**
425    * DOCUMENT ME!
426    * 
427    * @param value
428    *          DOCUMENT ME!
429    */
430   public void setValue(int value)
431   {
432     slider.setValue(value);
433   }
434
435   /**
436    * DOCUMENT ME!
437    * 
438    * @return DOCUMENT ME!
439    */
440   public int getValue()
441   {
442     return Integer.parseInt(valueField.getText());
443   }
444
445   @Override
446   public void slider_mouseReleased(MouseEvent e)
447   {
448     if (ap.overviewPanel != null)
449     {
450       ap.overviewPanel.updateOverviewImage();
451     }
452   }
453
454   public static int getConservationValue()
455   {
456     return getValue(conservationSlider);
457   }
458
459   static int getValue(JInternalFrame slider)
460   {
461     return slider == null ? 0
462             : ((SliderPanel) slider.getContentPane()).getValue();
463   }
464
465   public static int getPIDValue()
466   {
467     return getValue(PIDSlider);
468   }
469
470   /**
471    * Answers true if the SliderPanel is for Conservation, false if it is for PID
472    * threshold
473    * 
474    * @return
475    */
476   public boolean isForConservation()
477   {
478     return forConservation;
479   }
480
481   /**
482    * Answers the title for the slider panel; this may include 'Background' if
483    * for the alignment, or the group id if for a group
484    * 
485    * @return
486    */
487   public String getTitle()
488   {
489     String title = null;
490     if (isForConservation())
491     {
492       if (conservationSlider != null)
493       {
494         title = conservationSlider.getTitle();
495       }
496     }
497     else if (PIDSlider != null)
498     {
499       title = PIDSlider.getTitle();
500     }
501     return title;
502   }
503 }