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