JAL-1933 update threshold on focus lost in text field
[jalview.git] / src / jalview / gui / AnnotationRowFilter.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.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.GraphLine;
25 import jalview.datamodel.SequenceGroup;
26 import jalview.schemes.AnnotationColourGradient;
27 import jalview.util.MessageManager;
28
29 import java.awt.event.FocusAdapter;
30 import java.awt.event.FocusEvent;
31 import java.awt.event.MouseAdapter;
32 import java.awt.event.MouseEvent;
33 import java.util.Vector;
34
35 import javax.swing.JButton;
36 import javax.swing.JCheckBox;
37 import javax.swing.JComboBox;
38 import javax.swing.JInternalFrame;
39 import javax.swing.JPanel;
40 import javax.swing.JSlider;
41 import javax.swing.JTextField;
42 import javax.swing.event.ChangeEvent;
43 import javax.swing.event.ChangeListener;
44
45 @SuppressWarnings("serial")
46 public abstract class AnnotationRowFilter extends JPanel
47 {
48   protected AlignViewport av;
49
50   protected AlignmentPanel ap;
51
52   protected int[] annmap;
53
54   protected boolean enableSeqAss = false;
55
56   private AlignmentAnnotation currentAnnotation;
57
58   protected boolean adjusting = false;
59
60   protected JCheckBox currentColours = new JCheckBox();
61
62   protected JPanel minColour = new JPanel();
63
64   protected JPanel maxColour = new JPanel();
65
66   protected JCheckBox seqAssociated = new JCheckBox();
67
68   protected JCheckBox thresholdIsMin = new JCheckBox();
69
70   protected JSlider slider = new JSlider();
71
72   protected JTextField thresholdValue = new JTextField(20);
73
74   protected JInternalFrame frame;
75
76   protected JButton ok = new JButton();
77
78   protected JButton cancel = new JButton();
79
80   /**
81    * enabled if the user is dragging the slider - try to keep updates to a
82    * minimun
83    */
84   protected boolean sliderDragging = false;
85
86   protected void addSliderChangeListener()
87   {
88
89     slider.addChangeListener(new ChangeListener()
90     {
91       @Override
92       public void stateChanged(ChangeEvent evt)
93       {
94         if (!adjusting)
95         {
96           thresholdValue.setText((slider.getValue() / 1000f) + "");
97           valueChanged(!sliderDragging);
98         }
99       }
100     });
101   }
102
103   protected void addSliderMouseListeners()
104   {
105
106     slider.addMouseListener(new MouseAdapter()
107     {
108       @Override
109       public void mousePressed(MouseEvent e)
110       {
111         sliderDragging = true;
112         super.mousePressed(e);
113       }
114
115       @Override
116       public void mouseDragged(MouseEvent e)
117       {
118         sliderDragging = true;
119         super.mouseDragged(e);
120       }
121
122       @Override
123       public void mouseReleased(MouseEvent evt)
124       {
125         if (sliderDragging)
126         {
127           sliderDragging = false;
128           valueChanged(true);
129         }
130         ap.paintAlignment(true);
131       }
132     });
133   }
134
135   public AnnotationRowFilter(AlignViewport av, final AlignmentPanel ap)
136   {
137     this.av = av;
138     this.ap = ap;
139     thresholdValue.addFocusListener(new FocusAdapter()
140     {
141       @Override
142       public void focusLost(FocusEvent e)
143       {
144         thresholdValue_actionPerformed();
145       }
146     });
147   }
148
149   public AnnotationRowFilter()
150   {
151
152   }
153
154   public Vector<String> getAnnotationItems(boolean isSeqAssociated)
155   {
156     Vector<String> list = new Vector<String>();
157     int index = 1;
158     int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
159     for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
160     {
161       if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
162       {
163         if (isSeqAssociated)
164         {
165           continue;
166         }
167       }
168       else
169       {
170         enableSeqAss = true;
171       }
172       String label = av.getAlignment().getAlignmentAnnotation()[i].label;
173       // add associated sequence ID if available
174       if (!isSeqAssociated
175               && av.getAlignment().getAlignmentAnnotation()[i].sequenceRef != null)
176       {
177         label = label
178                 + "_"
179                 + av.getAlignment().getAlignmentAnnotation()[i].sequenceRef
180                         .getName();
181       }
182       // make label unique
183       if (!list.contains(label))
184       {
185         anmap[list.size()] = i;
186         list.add(label);
187       }
188       else
189       {
190         if (!isSeqAssociated)
191         {
192           anmap[list.size()] = i;
193           list.add(label + "_" + (index++));
194         }
195       }
196     }
197     this.annmap = new int[list.size()];
198     System.arraycopy(anmap, 0, this.annmap, 0, this.annmap.length);
199     return list;
200   }
201
202   protected int getSelectedThresholdItem(int indexValue)
203   {
204     int selectedThresholdItem = -1;
205     if (indexValue == 1)
206     {
207       selectedThresholdItem = AnnotationColourGradient.ABOVE_THRESHOLD;
208     }
209     else if (indexValue == 2)
210     {
211       selectedThresholdItem = AnnotationColourGradient.BELOW_THRESHOLD;
212     }
213     return selectedThresholdItem;
214   }
215
216   public void modelChanged()
217   {
218     seqAssociated.setEnabled(enableSeqAss);
219   }
220
221   public void ok_actionPerformed()
222   {
223     try
224     {
225       frame.setClosed(true);
226     } catch (Exception ex)
227     {
228     }
229   }
230
231   public void cancel_actionPerformed()
232   {
233     reset();
234     ap.paintAlignment(true);
235     try
236     {
237       frame.setClosed(true);
238     } catch (Exception ex)
239     {
240     }
241   }
242
243   public void thresholdCheck_actionPerformed()
244   {
245     updateView();
246   }
247
248   public void annotations_actionPerformed()
249   {
250     updateView();
251   }
252
253   public void threshold_actionPerformed()
254   {
255     updateView();
256   }
257
258   public void thresholdValue_actionPerformed()
259   {
260     try
261     {
262       float f = Float.parseFloat(thresholdValue.getText());
263       slider.setValue((int) (f * 1000));
264       updateView();
265     } catch (NumberFormatException ex)
266     {
267     }
268   }
269
270   public void thresholdIsMin_actionPerformed()
271   {
272     updateView();
273   }
274
275   protected void populateThresholdComboBox(JComboBox<String> threshold)
276   {
277     threshold.addItem(MessageManager
278             .getString("label.threshold_feature_no_threshold"));
279     threshold.addItem(MessageManager
280             .getString("label.threshold_feature_above_threshold"));
281     threshold.addItem(MessageManager
282             .getString("label.threshold_feature_below_threshold"));
283   }
284
285   protected void seqAssociated_actionPerformed(JComboBox<String> annotations)
286   {
287     adjusting = true;
288     String cursel = (String) annotations.getSelectedItem();
289     boolean isvalid = false, isseqs = seqAssociated.isSelected();
290     annotations.removeAllItems();
291     for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
292     {
293       if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
294       {
295         isvalid = true;
296         cursel = anitem;
297       }
298       annotations.addItem(anitem);
299     }
300     adjusting = false;
301     if (isvalid)
302     {
303       annotations.setSelectedItem(cursel);
304     }
305     else
306     {
307       if (annotations.getItemCount() > 0)
308       {
309         annotations.setSelectedIndex(0);
310       }
311     }
312   }
313
314   protected void propagateSeqAssociatedThreshold(boolean allAnnotation,
315           AlignmentAnnotation annotation)
316   {
317     if (annotation.sequenceRef == null || annotation.threshold == null)
318     {
319       return;
320     }
321
322     float thr = annotation.threshold.value;
323     for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
324     {
325       AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
326       if (aa.label.equals(annotation.label)
327               && (annotation.getCalcId() == null ? aa.getCalcId() == null
328                       : annotation.getCalcId().equals(aa.getCalcId())))
329       {
330         if (aa.threshold == null)
331         {
332           aa.threshold = new GraphLine(annotation.threshold);
333         }
334         else
335         {
336           aa.threshold.value = thr;
337         }
338       }
339     }
340   }
341
342   protected boolean colorAlignmContaining(AlignmentAnnotation currentAnn,
343           int selectedThresholdOption)
344   {
345
346     AnnotationColourGradient acg = null;
347     if (currentColours.isSelected())
348     {
349       acg = new AnnotationColourGradient(currentAnn,
350               av.getGlobalColourScheme(), selectedThresholdOption);
351     }
352     else
353     {
354       acg = new AnnotationColourGradient(currentAnn,
355               minColour.getBackground(), maxColour.getBackground(),
356               selectedThresholdOption);
357     }
358     acg.setSeqAssociated(seqAssociated.isSelected());
359
360     if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
361     {
362       acg.setPredefinedColours(true);
363     }
364
365     acg.thresholdIsMinMax = thresholdIsMin.isSelected();
366
367     av.setGlobalColourScheme(acg);
368
369     if (av.getAlignment().getGroups() != null)
370     {
371
372       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
373       {
374         if (sg.cs == null)
375         {
376           continue;
377         }
378
379         if (currentColours.isSelected())
380         {
381           sg.cs = new AnnotationColourGradient(currentAnn, sg.cs,
382                   selectedThresholdOption);
383           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
384                   .isSelected());
385
386         }
387         else
388         {
389           sg.cs = new AnnotationColourGradient(currentAnn,
390                   minColour.getBackground(), maxColour.getBackground(),
391                   selectedThresholdOption);
392           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
393                   .isSelected());
394         }
395
396       }
397     }
398     return false;
399   }
400
401   public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation()
402   {
403     return currentAnnotation;
404   }
405
406   public void setCurrentAnnotation(
407           jalview.datamodel.AlignmentAnnotation currentAnnotation)
408   {
409     this.currentAnnotation = currentAnnotation;
410   }
411
412   public abstract void valueChanged(boolean updateAllAnnotation);
413
414   public abstract void updateView();
415
416   public abstract void reset();
417 }