JAL-1553 enhancement of column selection by annotation row to include the query filte...
[jalview.git] / src / jalview / gui / AnnotationRowFilter.java
1 package jalview.gui;
2
3 import jalview.api.AnnotationRowFilterI;
4 import jalview.datamodel.AlignmentAnnotation;
5 import jalview.datamodel.Annotation;
6 import jalview.datamodel.AnnotationFilterParameter;
7 import jalview.datamodel.AnnotationFilterParameter.SearchableAnnotationField;
8 import jalview.datamodel.ColumnSelection;
9 import jalview.datamodel.GraphLine;
10 import jalview.datamodel.SequenceGroup;
11 import jalview.schemes.AnnotationColourGradient;
12 import jalview.util.MessageManager;
13
14 import java.awt.event.ActionEvent;
15 import java.awt.event.MouseAdapter;
16 import java.awt.event.MouseEvent;
17 import java.util.List;
18 import java.util.Vector;
19
20 import javax.swing.JCheckBox;
21 import javax.swing.JComboBox;
22 import javax.swing.JInternalFrame;
23 import javax.swing.JPanel;
24 import javax.swing.JSlider;
25 import javax.swing.JTextField;
26 import javax.swing.event.ChangeEvent;
27 import javax.swing.event.ChangeListener;
28
29 @SuppressWarnings("serial")
30 public abstract class AnnotationRowFilter extends JPanel implements
31         AnnotationRowFilterI
32 {
33   protected AlignViewport av;
34
35   protected AlignmentPanel ap;
36
37   protected int[] annmap;
38
39   protected boolean enableSeqAss = false;
40
41   private jalview.datamodel.AlignmentAnnotation currentAnnotation;
42
43   protected boolean adjusting = false;
44
45   protected JCheckBox currentColours = new JCheckBox();
46
47   protected JPanel minColour = new JPanel();
48
49   protected JPanel maxColour = new JPanel();
50
51   protected JCheckBox seqAssociated = new JCheckBox();
52
53   protected JCheckBox thresholdIsMin = new JCheckBox();
54
55   protected JSlider slider = new JSlider();
56
57   protected JTextField thresholdValue = new JTextField(20);
58
59   protected JInternalFrame frame;
60   /**
61    * enabled if the user is dragging the slider - try to keep updates to a
62    * minimun
63    */
64   protected boolean sliderDragging = false;
65
66   protected void addSliderChangeListener()
67   {
68
69     slider.addChangeListener(new ChangeListener()
70     {
71       @Override
72       public void stateChanged(ChangeEvent evt)
73       {
74         if (!adjusting)
75         {
76           thresholdValue.setText((slider.getValue() / 1000f) + "");
77           valueChanged(!sliderDragging);
78         }
79       }
80     });
81   }
82
83   protected void addSliderMouseListeners()
84   {
85
86     slider.addMouseListener(new MouseAdapter()
87     {
88       @Override
89       public void mousePressed(MouseEvent e)
90       {
91         sliderDragging = true;
92         super.mousePressed(e);
93       }
94
95       @Override
96       public void mouseDragged(MouseEvent e)
97       {
98         sliderDragging = true;
99         super.mouseDragged(e);
100       }
101
102       @Override
103       public void mouseReleased(MouseEvent evt)
104       {
105         if (sliderDragging)
106         {
107           sliderDragging = false;
108           valueChanged(true);
109         }
110         ap.paintAlignment(true);
111       }
112     });
113   }
114
115
116   public AnnotationRowFilter(AlignViewport av, final AlignmentPanel ap)
117   {
118     this.av = av;
119     this.ap = ap;
120   }
121
122   public AnnotationRowFilter()
123   {
124
125   }
126
127   @Override
128   public Vector<String> getAnnotationItems(boolean isSeqAssociated)
129   {
130     Vector<String> list = new Vector<String>();
131     int index = 1;
132     int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
133     for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
134     {
135       if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
136       {
137         if (isSeqAssociated)
138         {
139           continue;
140         }
141       }
142       else
143       {
144         enableSeqAss = true;
145       }
146       String label = av.getAlignment().getAlignmentAnnotation()[i].label;
147       if (!list.contains(label))
148       {
149         anmap[list.size()] = i;
150         list.add(label);
151
152       }
153       else
154       {
155         if (!isSeqAssociated)
156         {
157           anmap[list.size()] = i;
158           list.add(label + "_" + (index++));
159         }
160       }
161     }
162     this.annmap = new int[list.size()];
163     System.arraycopy(anmap, 0, this.annmap, 0, this.annmap.length);
164     return list;
165   }
166
167   protected int getSelectedThresholdItem(int indexValue)
168   {
169     int selectedThresholdItem = -1;
170     if (indexValue == 1)
171     {
172       selectedThresholdItem = AnnotationColourGradient.ABOVE_THRESHOLD;
173     }
174     else if (indexValue == 2)
175     {
176       selectedThresholdItem = AnnotationColourGradient.BELOW_THRESHOLD;
177     }
178     return selectedThresholdItem;
179   }
180
181   public void modelChanged()
182   {
183     seqAssociated.setEnabled(enableSeqAss);
184   }
185
186   public void ok_actionPerformed(ActionEvent e)
187   {
188     updateView();
189     try
190     {
191       frame.setClosed(true);
192     } catch (Exception ex)
193     {
194     }
195   }
196
197   public void cancel_actionPerformed(ActionEvent e)
198   {
199     reset();
200     ap.paintAlignment(true);
201     try
202     {
203       frame.setClosed(true);
204     } catch (Exception ex)
205     {
206     }
207   }
208
209   public void thresholdCheck_actionPerformed(ActionEvent e)
210   {
211     updateView();
212   }
213
214   public void annotations_actionPerformed(ActionEvent e)
215   {
216     updateView();
217   }
218
219   public void threshold_actionPerformed(ActionEvent e)
220   {
221     updateView();
222   }
223
224   public void thresholdValue_actionPerformed(ActionEvent e)
225   {
226     try
227     {
228       float f = Float.parseFloat(thresholdValue.getText());
229       slider.setValue((int) (f * 1000));
230       updateView();
231     } catch (NumberFormatException ex)
232     {
233     }
234   }
235
236   public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
237   {
238     updateView();
239   }
240
241   protected void populateThresholdComboBox(JComboBox<String> threshold)
242   {
243     threshold.addItem(MessageManager
244             .getString("label.threshold_feature_no_thereshold"));
245     threshold.addItem(MessageManager
246             .getString("label.threshold_feature_above_thereshold"));
247     threshold.addItem(MessageManager
248             .getString("label.threshold_feature_below_thereshold"));
249   }
250
251   protected void seqAssociated_actionPerformed(ActionEvent arg0,
252           JComboBox<String> annotations, JCheckBox seqAssociated)
253   {
254     adjusting = true;
255     String cursel = (String) annotations.getSelectedItem();
256     boolean isvalid = false, isseqs = seqAssociated.isSelected();
257     annotations.removeAllItems();
258     for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
259     {
260       if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
261       {
262         isvalid = true;
263         cursel = anitem;
264       }
265       annotations.addItem(anitem);
266     }
267     adjusting = false;
268     if (isvalid)
269     {
270       annotations.setSelectedItem(cursel);
271     }
272     else
273     {
274       if (annotations.getItemCount() > 0)
275       {
276         annotations.setSelectedIndex(0);
277       }
278     }
279   }
280
281   protected void propagateSeqAssociatedThreshold(boolean allAnnotation,
282           AlignmentAnnotation annotation)
283   {
284     if (annotation.sequenceRef == null || annotation.threshold == null)
285     {
286       return;
287     }
288
289     float thr = annotation.threshold.value;
290     for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
291     {
292       AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
293       if (aa.label.equals(annotation.label)
294               && (annotation.getCalcId() == null ? aa.getCalcId() == null
295                       : annotation.getCalcId().equals(aa.getCalcId())))
296       {
297         if (aa.threshold == null)
298         {
299           aa.threshold = new GraphLine(annotation.threshold);
300         }
301         else
302         {
303           aa.threshold.value = thr;
304         }
305       }
306     }
307   }
308
309   protected boolean colorAlignmContaining(
310           AlignmentAnnotation currentAnnotation, int selectedThresholdItem)
311   {
312
313     AnnotationColourGradient acg = null;
314     if (currentColours.isSelected())
315     {
316       acg = new AnnotationColourGradient(currentAnnotation,
317               av.getGlobalColourScheme(), selectedThresholdItem);
318     }
319     else
320     {
321       acg = new AnnotationColourGradient(currentAnnotation,
322               minColour.getBackground(), maxColour.getBackground(),
323               selectedThresholdItem);
324     }
325     acg.setSeqAssociated(seqAssociated.isSelected());
326
327     if (currentAnnotation.graphMin == 0f
328             && currentAnnotation.graphMax == 0f)
329     {
330       acg.setPredefinedColours(true);
331     }
332
333     acg.thresholdIsMinMax = thresholdIsMin.isSelected();
334
335     av.setGlobalColourScheme(acg);
336
337     if (av.getAlignment().getGroups() != null)
338     {
339
340       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
341       {
342         if (sg.cs == null)
343         {
344           continue;
345         }
346
347         if (currentColours.isSelected())
348         {
349           sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
350                   selectedThresholdItem);
351           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
352                   .isSelected());
353
354         }
355         else
356         {
357           sg.cs = new AnnotationColourGradient(currentAnnotation,
358                   minColour.getBackground(), maxColour.getBackground(),
359                   selectedThresholdItem);
360           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
361                   .isSelected());
362         }
363
364       }
365     }
366     return false;
367   }
368
369   protected boolean filterAnnotations(Annotation[] annotations,
370           AnnotationFilterParameter filterParams, ColumnSelection cs)
371   {
372     av.showAllHiddenColumns();
373     cs.clear();
374     int count = 0;
375     do
376     {
377       if (annotations[count] != null)
378       {
379
380         boolean itemMatched = false;
381
382         if (filterParams.getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD
383                 && annotations[count].value > currentAnnotation.threshold.value)
384         {
385           itemMatched = true;
386         }
387         if (filterParams.getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD
388                 && annotations[count].value < currentAnnotation.threshold.value)
389         {
390           itemMatched = true;
391         }
392
393         if (filterParams.isFilterAlphaHelix()
394                 && annotations[count].secondaryStructure == 'H')
395         {
396           itemMatched = true;
397         }
398
399         if (filterParams.isFilterBetaSheet()
400                 && annotations[count].secondaryStructure == 'E')
401         {
402           itemMatched = true;
403         }
404
405         if (filterParams.isFilterTurn()
406                 && annotations[count].secondaryStructure == 'S')
407         {
408           itemMatched = true;
409         }
410
411         String regexSearchString = filterParams.getRegexString();
412         if (regexSearchString != null
413                 && !filterParams.getRegexSearchFields().isEmpty())
414         {
415           List<SearchableAnnotationField> fields = filterParams
416                   .getRegexSearchFields();
417           try
418           {
419             if (fields.contains(SearchableAnnotationField.DISPLAY_STRING)
420                     && annotations[count].displayCharacter
421                             .matches(regexSearchString))
422             {
423               itemMatched = true;
424             }
425           } catch (java.util.regex.PatternSyntaxException pse)
426           {
427             if (annotations[count].displayCharacter
428                     .equals(regexSearchString))
429             {
430               itemMatched = true;
431             }
432           }
433           if (fields.contains(SearchableAnnotationField.DESCRIPTION)
434                   && annotations[count].description != null
435                   && annotations[count].description
436                           .matches(regexSearchString))
437           {
438             itemMatched = true;
439           }
440         }
441
442         if (itemMatched)
443         {
444           cs.addElement(count);
445         }
446       }
447       count++;
448     } while (count < annotations.length);
449     return false;
450   }
451
452   public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation()
453   {
454     return currentAnnotation;
455   }
456
457   public void setCurrentAnnotation(
458           jalview.datamodel.AlignmentAnnotation currentAnnotation)
459   {
460     this.currentAnnotation = currentAnnotation;
461   }
462
463 }