Merge branch 'JAL-3878_ws-overhaul-3' into with_ws_overhaul-3
[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.setContentPane(sliderPanel);
160       conservationSlider.setLayer(JLayeredPane.PALETTE_LAYER);
161     }
162     else
163     {
164       sliderPanel = (SliderPanel) conservationSlider.getContentPane();
165       sliderPanel.valueField
166               .setText(String.valueOf(rs.getConservationInc()));
167       sliderPanel.cs = rs;
168       sliderPanel.ap = ap;
169       sliderPanel.slider.setValue(rs.getConservationInc());
170     }
171
172     conservationSlider.setTitle(MessageManager.formatMessage(
173             "label.conservation_colour_increment", new String[]
174             { source == null ? BACKGROUND : source }));
175
176     List<SequenceGroup> groups = ap.av.getAlignment().getGroups();
177     if (groups != null && !groups.isEmpty())
178     {
179       sliderPanel.setAllGroupsCheckEnabled(true);
180       sliderPanel.allGroupsCheck
181               .setSelected(ap.av.getColourAppliesToAllGroups());
182     }
183     else
184     {
185       sliderPanel.setAllGroupsCheckEnabled(false);
186     }
187
188     return sliderPanel.getValue();
189   }
190
191   /**
192    * Hides the PID slider panel if it is shown
193    */
194   public static void hidePIDSlider()
195   {
196     if (PIDSlider != null)
197     {
198       try
199       {
200         PIDSlider.setClosed(true);
201         PIDSlider = null;
202       } catch (PropertyVetoException ex)
203       {
204       }
205     }
206   }
207
208   /**
209    * Hides the conservation slider panel if it is shown
210    */
211   public static void hideConservationSlider()
212   {
213     if (conservationSlider != null)
214     {
215       try
216       {
217         conservationSlider.setClosed(true);
218         conservationSlider = null;
219       } catch (PropertyVetoException ex)
220       {
221       }
222     }
223   }
224
225   /**
226    * DOCUMENT ME!
227    */
228   public static void showConservationSlider()
229   {
230     hidePIDSlider();
231
232     if (!conservationSlider.isVisible())
233     {
234       Desktop.addInternalFrame(conservationSlider,
235               conservationSlider.getTitle(), Desktop.FRAME_MAKE_VISIBLE, FRAME_WIDTH,
236               FRAME_HEIGHT, Desktop.FRAME_NOT_RESIZABLE, Desktop.FRAME_ALLOW_ANY_SIZE);
237       conservationSlider.addInternalFrameListener(new InternalFrameAdapter()
238       {
239         @Override
240         public void internalFrameClosed(InternalFrameEvent e)
241         {
242           conservationSlider = null;
243         }
244       });
245       conservationSlider.setLayer(JLayeredPane.PALETTE_LAYER);
246     }
247   }
248
249   /**
250    * Method to 'set focus' of the PID slider panel
251    * 
252    * @param ap
253    *          the panel to repaint on change of slider
254    * @param rs
255    *          the colour scheme to update on change of slider
256    * @param source
257    *          a text description for the panel's title
258    * 
259    * @return
260    */
261   public static int setPIDSliderSource(AlignmentPanel ap, ResidueShaderI rs,
262           String source)
263   {
264     int threshold = rs.getThreshold();
265
266     SliderPanel sliderPanel = null;
267
268     if (PIDSlider == null)
269     {
270       sliderPanel = new SliderPanel(ap, threshold, false, rs);
271       PIDSlider = new JInternalFrame();
272       PIDSlider.setContentPane(sliderPanel);
273       PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER);
274     }
275     else
276     {
277       sliderPanel = (SliderPanel) PIDSlider.getContentPane();
278       sliderPanel.cs = rs;
279       sliderPanel.ap = ap;
280       sliderPanel.valueField.setText(String.valueOf(rs.getThreshold()));
281       sliderPanel.slider.setValue(rs.getThreshold());
282     }
283
284     PIDSlider.setTitle(MessageManager.formatMessage(
285             "label.percentage_identity_threshold", new String[]
286             { source == null ? BACKGROUND : source }));
287
288     if (ap.av.getAlignment().getGroups() != null)
289     {
290       sliderPanel.setAllGroupsCheckEnabled(true);
291     }
292     else
293     {
294       sliderPanel.setAllGroupsCheckEnabled(false);
295     }
296
297     return sliderPanel.getValue();
298   }
299
300   /**
301    * DOCUMENT ME!
302    * 
303    * @return
304    */
305   public static JInternalFrame showPIDSlider()
306   {
307     hideConservationSlider();
308
309     if (!PIDSlider.isVisible())
310     {
311       Desktop.addInternalFrame(PIDSlider, PIDSlider.getTitle(), Desktop.FRAME_MAKE_VISIBLE,
312               FRAME_WIDTH, FRAME_HEIGHT, Desktop.FRAME_NOT_RESIZABLE, Desktop.FRAME_ALLOW_ANY_SIZE);
313       PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER);
314       PIDSlider.addInternalFrameListener(new InternalFrameAdapter()
315       {
316         @Override
317         public void internalFrameClosed(InternalFrameEvent e)
318         {
319           PIDSlider = null;
320         }
321       });
322       PIDSlider.setLayer(JLayeredPane.PALETTE_LAYER);
323     }
324     return PIDSlider;
325   }
326
327   /**
328    * Updates the colour scheme with the current (identity threshold or
329    * conservation) percentage value. Also updates all groups if 'apply to all
330    * groups' is selected.
331    * 
332    * @param percent
333    */
334   public void valueChanged(int percent)
335   {
336     if (!forConservation)
337     {
338       ap.av.setThreshold(percent);
339     }
340     updateColourScheme(percent, cs, null);
341
342     if (allGroupsCheck.isSelected())
343     {
344       List<SequenceGroup> groups = ap.av.getAlignment().getGroups();
345       for (SequenceGroup sg : groups)
346       {
347         updateColourScheme(percent, sg.getGroupColourScheme(), sg);
348       }
349     }
350
351     ap.getSeqPanel().seqCanvas.repaint();
352   }
353
354   /**
355    * Updates the colour scheme (if not null) with the current (identity
356    * threshold or conservation) percentage value
357    * 
358    * @param percent
359    * @param scheme
360    * @param sg
361    */
362   protected void updateColourScheme(int percent, ResidueShaderI scheme,
363           SequenceGroup sg)
364   {
365     if (scheme == null)
366     {
367       return;
368     }
369     if (forConservation)
370     {
371       if (!scheme.conservationApplied() && sg != null)
372       {
373         /*
374          * first time the colour scheme has had Conservation shading applied
375          * - compute conservation
376          */
377         Conservation c = new Conservation("Group", sg.getSequences(null),
378                 sg.getStartRes(), sg.getEndRes());
379         c.calculate();
380         c.verdict(false, ap.av.getConsPercGaps());
381         sg.cs.setConservation(c);
382
383       }
384       scheme.setConservationApplied(true);
385       scheme.setConservationInc(percent);
386     }
387     else
388     {
389       scheme.setThreshold(percent, ap.av.isIgnoreGapsConsensus());
390     }
391   }
392
393   /**
394    * DOCUMENT ME!
395    * 
396    * @param b
397    *          DOCUMENT ME!
398    */
399   public void setAllGroupsCheckEnabled(boolean b)
400   {
401     allGroupsCheck.setEnabled(b);
402   }
403
404   /**
405    * DOCUMENT ME!
406    * 
407    * @param e
408    *          DOCUMENT ME!
409    */
410   @Override
411   public void valueField_actionPerformed()
412   {
413     try
414     {
415       int i = Integer.parseInt(valueField.getText());
416       slider.setValue(i);
417     } catch (NumberFormatException ex)
418     {
419       valueField.setText(slider.getValue() + "");
420     }
421   }
422
423   /**
424    * DOCUMENT ME!
425    * 
426    * @param value
427    *          DOCUMENT ME!
428    */
429   public void setValue(int value)
430   {
431     slider.setValue(value);
432   }
433
434   /**
435    * DOCUMENT ME!
436    * 
437    * @return DOCUMENT ME!
438    */
439   public int getValue()
440   {
441     return Integer.parseInt(valueField.getText());
442   }
443
444   @Override
445   public void slider_mouseReleased(MouseEvent e)
446   {
447     if (ap.overviewPanel != null)
448     {
449       ap.overviewPanel.updateOverviewImage();
450     }
451   }
452
453   public static int getConservationValue()
454   {
455     return getValue(conservationSlider);
456   }
457
458   static int getValue(JInternalFrame slider)
459   {
460     return slider == null ? 0
461             : ((SliderPanel) slider.getContentPane()).getValue();
462   }
463
464   public static int getPIDValue()
465   {
466     return getValue(PIDSlider);
467   }
468
469   /**
470    * Answers true if the SliderPanel is for Conservation, false if it is for PID
471    * threshold
472    * 
473    * @return
474    */
475   public boolean isForConservation()
476   {
477     return forConservation;
478   }
479
480   /**
481    * Answers the title for the slider panel; this may include 'Background' if
482    * for the alignment, or the group id if for a group
483    * 
484    * @return
485    */
486   public String getTitle()
487   {
488     String title = null;
489     if (isForConservation())
490     {
491       if (conservationSlider != null)
492       {
493         title = conservationSlider.getTitle();
494       }
495     }
496     else if (PIDSlider != null)
497     {
498       title = PIDSlider.getTitle();
499     }
500     return title;
501   }
502 }