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