JAL-2346 disable 'threshold min/max' when 'use original colours'
[jalview.git] / src / jalview / gui / AnnotationColourChooser.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.bin.Cache;
24 import jalview.datamodel.AlignmentAnnotation;
25 import jalview.datamodel.GraphLine;
26 import jalview.datamodel.SequenceGroup;
27 import jalview.schemes.AnnotationColourGradient;
28 import jalview.schemes.ColourSchemeI;
29 import jalview.util.MessageManager;
30
31 import java.awt.BorderLayout;
32 import java.awt.Color;
33 import java.awt.Dimension;
34 import java.awt.FlowLayout;
35 import java.awt.event.ActionEvent;
36 import java.awt.event.ActionListener;
37 import java.awt.event.MouseAdapter;
38 import java.awt.event.MouseEvent;
39 import java.util.Hashtable;
40 import java.util.Vector;
41
42 import javax.swing.BorderFactory;
43 import javax.swing.JButton;
44 import javax.swing.JCheckBox;
45 import javax.swing.JColorChooser;
46 import javax.swing.JComboBox;
47 import javax.swing.JInternalFrame;
48 import javax.swing.JLayeredPane;
49 import javax.swing.JPanel;
50
51 import net.miginfocom.swing.MigLayout;
52
53 @SuppressWarnings("serial")
54 public class AnnotationColourChooser extends AnnotationRowFilter
55 {
56   private static final int ONETHOUSAND = 1000;
57
58   private ColourSchemeI oldcs;
59
60   private JButton defColours;
61
62   private Hashtable<SequenceGroup, ColourSchemeI> oldgroupColours;
63
64   private JCheckBox useOriginalColours = new JCheckBox();
65
66   private JPanel minColour = new JPanel();
67
68   private JPanel maxColour = new JPanel();
69
70   private JCheckBox thresholdIsMin = new JCheckBox();
71
72   public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
73   {
74     super(av, ap);
75     oldcs = av.getGlobalColourScheme();
76     if (av.getAlignment().getGroups() != null)
77     {
78       oldgroupColours = new Hashtable<SequenceGroup, ColourSchemeI>();
79       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
80       {
81         if (sg.getColourScheme() != null)
82         {
83           oldgroupColours.put(sg, sg.getColourScheme());
84         }
85       }
86     }
87     frame = new JInternalFrame();
88     frame.setContentPane(this);
89     frame.setLayer(JLayeredPane.PALETTE_LAYER);
90     Desktop.addInternalFrame(frame,
91             MessageManager.getString("label.colour_by_annotation"), 520,
92             215);
93
94     addSliderChangeListener();
95     addSliderMouseListeners();
96
97     if (av.getAlignment().getAlignmentAnnotation() == null)
98     {
99       return;
100     }
101
102     // Always get default shading from preferences.
103     setDefaultMinMax();
104
105     adjusting = true;
106     if (oldcs instanceof AnnotationColourGradient)
107     {
108       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
109       useOriginalColours.setSelected(acg.isPredefinedColours()
110               || acg.getBaseColour() != null);
111       if (!acg.isPredefinedColours() && acg.getBaseColour() == null)
112       {
113         minColour.setBackground(acg.getMinColour());
114         maxColour.setBackground(acg.getMaxColour());
115       }
116       seqAssociated.setSelected(acg.isSeqAssociated());
117
118     }
119     Vector<String> annotItems = getAnnotationItems(seqAssociated
120             .isSelected());
121     annotations = new JComboBox<String>(annotItems);
122
123     populateThresholdComboBox(threshold);
124
125     if (oldcs instanceof AnnotationColourGradient)
126     {
127       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
128       String label = getAnnotationMenuLabel(acg.getAnnotation());
129       annotations.setSelectedItem(label);
130       switch (acg.getAboveThreshold())
131       {
132       case AnnotationColourGradient.NO_THRESHOLD:
133         getThreshold().setSelectedIndex(0);
134         break;
135       case AnnotationColourGradient.ABOVE_THRESHOLD:
136         getThreshold().setSelectedIndex(1);
137         break;
138       case AnnotationColourGradient.BELOW_THRESHOLD:
139         getThreshold().setSelectedIndex(2);
140         break;
141       default:
142         throw new Error(
143                 MessageManager
144                         .getString("error.implementation_error_dont_know_about_threshold_setting"));
145       }
146       thresholdIsMin.setSelected(acg.isThresholdIsMinMax());
147       thresholdValue.setText("" + acg.getAnnotationThreshold());
148     }
149
150     jbInit();
151     adjusting = false;
152
153     updateView();
154     frame.invalidate();
155     frame.pack();
156   }
157
158   @Override
159   protected void jbInit()
160   {
161     super.jbInit();
162
163     minColour.setFont(JvSwingUtils.getLabelFont());
164     minColour.setBorder(BorderFactory.createEtchedBorder());
165     minColour.setPreferredSize(new Dimension(40, 20));
166     minColour.setToolTipText(MessageManager.getString("label.min_colour"));
167     minColour.addMouseListener(new MouseAdapter()
168     {
169       @Override
170       public void mousePressed(MouseEvent e)
171       {
172         if (minColour.isEnabled())
173         {
174           minColour_actionPerformed();
175         }
176       }
177     });
178     maxColour.setFont(JvSwingUtils.getLabelFont());
179     maxColour.setBorder(BorderFactory.createEtchedBorder());
180     maxColour.setPreferredSize(new Dimension(40, 20));
181     maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
182     maxColour.addMouseListener(new MouseAdapter()
183     {
184       @Override
185       public void mousePressed(MouseEvent e)
186       {
187         if (maxColour.isEnabled())
188         {
189           maxColour_actionPerformed();
190         }
191       }
192     });
193
194     defColours = new JButton();
195     defColours.setOpaque(false);
196     defColours.setText(MessageManager.getString("action.set_defaults"));
197     defColours.setToolTipText(MessageManager
198             .getString("label.reset_min_max_colours_to_defaults"));
199     defColours.addActionListener(new ActionListener()
200     {
201
202       @Override
203       public void actionPerformed(ActionEvent arg0)
204       {
205         resetColours_actionPerformed();
206       }
207     });
208
209     useOriginalColours.setFont(JvSwingUtils.getLabelFont());
210     useOriginalColours.setOpaque(false);
211     useOriginalColours.setText(MessageManager
212             .getString("label.use_original_colours"));
213     useOriginalColours.addActionListener(new ActionListener()
214     {
215       @Override
216       public void actionPerformed(ActionEvent e)
217       {
218         originalColours_actionPerformed();
219       }
220     });
221     thresholdIsMin.setBackground(Color.white);
222     thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
223     thresholdIsMin.setText(MessageManager
224             .getString("label.threshold_minmax"));
225     thresholdIsMin.addActionListener(new ActionListener()
226     {
227       @Override
228       public void actionPerformed(ActionEvent actionEvent)
229       {
230         thresholdIsMin_actionPerformed();
231       }
232     });
233     seqAssociated.setBackground(Color.white);
234     seqAssociated.setFont(JvSwingUtils.getLabelFont());
235     seqAssociated.setText(MessageManager
236             .getString("label.per_sequence_only"));
237     seqAssociated.addActionListener(new ActionListener()
238     {
239
240       @Override
241       public void actionPerformed(ActionEvent arg0)
242       {
243         seqAssociated_actionPerformed(annotations);
244       }
245     });
246
247     this.setLayout(new BorderLayout());
248     JPanel jPanel1 = new JPanel();
249     JPanel jPanel2 = new JPanel();
250     jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
251     jPanel1.setBackground(Color.white);
252     jPanel2.setBackground(Color.white);
253
254     jPanel1.add(ok);
255     jPanel1.add(cancel);
256     jPanel2.add(annotations, "grow, wrap");
257     jPanel2.add(seqAssociated);
258     jPanel2.add(useOriginalColours);
259     JPanel colpanel = new JPanel(new FlowLayout());
260     colpanel.setBackground(Color.white);
261     colpanel.add(minColour);
262     colpanel.add(maxColour);
263     jPanel2.add(colpanel, "wrap");
264     jPanel2.add(getThreshold());
265     jPanel2.add(defColours, "skip 1, wrap");
266     jPanel2.add(thresholdIsMin);
267     jPanel2.add(slider, "grow");
268     jPanel2.add(thresholdValue, "grow");
269     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
270     this.add(jPanel2, java.awt.BorderLayout.CENTER);
271     this.validate();
272   }
273
274   protected void resetColours_actionPerformed()
275   {
276     setDefaultMinMax();
277     updateView();
278   }
279
280   private void setDefaultMinMax()
281   {
282     minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
283             Color.orange));
284     maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
285             Color.red));
286   }
287
288   public void minColour_actionPerformed()
289   {
290     Color col = JColorChooser.showDialog(this,
291             MessageManager.getString("label.select_colour_minimum_value"),
292             minColour.getBackground());
293     if (col != null)
294     {
295       minColour.setBackground(col);
296     }
297     minColour.repaint();
298     updateView();
299   }
300
301   public void maxColour_actionPerformed()
302   {
303     Color col = JColorChooser.showDialog(this,
304             MessageManager.getString("label.select_colour_maximum_value"),
305             maxColour.getBackground());
306     if (col != null)
307     {
308       maxColour.setBackground(col);
309     }
310     maxColour.repaint();
311     updateView();
312   }
313
314   @Override
315   public void reset()
316   {
317     av.setGlobalColourScheme(oldcs);
318     if (av.getAlignment().getGroups() != null)
319     {
320
321       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
322       {
323         sg.setColourScheme(oldgroupColours.get(sg));
324       }
325     }
326   }
327
328   @Override
329   public void valueChanged(boolean updateAllAnnotation)
330   {
331     if (slider.isEnabled())
332     {
333       if (useOriginalColours.isSelected()
334               && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
335       {
336         updateView();
337       }
338       getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
339       propagateSeqAssociatedThreshold(updateAllAnnotation,
340               getCurrentAnnotation());
341       ap.paintAlignment(false);
342     }
343   }
344
345   public void originalColours_actionPerformed()
346   {
347     boolean selected = useOriginalColours.isSelected();
348     if (selected)
349     {
350       reset();
351     }
352     maxColour.setEnabled(!selected);
353     minColour.setEnabled(!selected);
354     thresholdIsMin.setEnabled(!selected);
355     updateView();
356   }
357
358   @Override
359   public void updateView()
360   {
361     // Check if combobox is still adjusting
362     if (adjusting)
363     {
364       return;
365     }
366
367     setCurrentAnnotation(av.getAlignment().getAlignmentAnnotation()[annmap[annotations
368             .getSelectedIndex()]]);
369
370     int selectedThresholdItem = getSelectedThresholdItem(getThreshold()
371             .getSelectedIndex());
372
373     slider.setEnabled(true);
374     thresholdValue.setEnabled(true);
375     thresholdIsMin.setEnabled(!useOriginalColours.isSelected());
376
377     if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
378     {
379       slider.setEnabled(false);
380       thresholdValue.setEnabled(false);
381       thresholdValue.setText("");
382       thresholdIsMin.setEnabled(false);
383     }
384     else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD
385             && getCurrentAnnotation().threshold == null)
386     {
387       getCurrentAnnotation()
388               .setThreshold(
389                       new GraphLine(
390                               (getCurrentAnnotation().graphMax - getCurrentAnnotation().graphMin) / 2f,
391                               "Threshold", Color.black));
392     }
393
394     if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
395     {
396       adjusting = true;
397       float range = getCurrentAnnotation().graphMax * ONETHOUSAND
398               - getCurrentAnnotation().graphMin * ONETHOUSAND;
399
400       slider.setMinimum((int) (getCurrentAnnotation().graphMin * ONETHOUSAND));
401       slider.setMaximum((int) (getCurrentAnnotation().graphMax * ONETHOUSAND));
402       slider.setValue((int) (getCurrentAnnotation().threshold.value * ONETHOUSAND));
403       thresholdValue.setText(getCurrentAnnotation().threshold.value + "");
404       slider.setMajorTickSpacing((int) (range / 10f));
405       slider.setEnabled(true);
406       thresholdValue.setEnabled(true);
407       adjusting = false;
408     }
409     colorAlignmentContaining(getCurrentAnnotation(), selectedThresholdItem);
410
411     ap.alignmentChanged();
412     // ensure all associated views (overviews, structures, etc) are notified of
413     // updated colours.
414     ap.paintAlignment(true);
415   }
416
417   protected boolean colorAlignmentContaining(AlignmentAnnotation currentAnn, int selectedThresholdOption)
418   {
419   
420     AnnotationColourGradient acg = null;
421     if (useOriginalColours.isSelected())
422     {
423       acg = new AnnotationColourGradient(currentAnn,
424               av.getGlobalColourScheme(), selectedThresholdOption);
425     }
426     else
427     {
428       acg = new AnnotationColourGradient(currentAnn,
429               minColour.getBackground(), maxColour.getBackground(),
430               selectedThresholdOption);
431     }
432     acg.setSeqAssociated(seqAssociated.isSelected());
433   
434     if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
435     {
436       acg.setPredefinedColours(true);
437     }
438   
439     acg.setThresholdIsMinMax(thresholdIsMin.isSelected());
440   
441     av.setGlobalColourScheme(acg);
442   
443     if (av.getAlignment().getGroups() != null)
444     {
445   
446       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
447       {
448         if (sg.cs == null)
449         {
450           continue;
451         }
452   
453         if (useOriginalColours.isSelected())
454         {
455           sg.setColourScheme(new AnnotationColourGradient(currentAnn, sg
456                   .getColourScheme(), selectedThresholdOption));
457           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
458                   .isSelected());
459         }
460         else
461         {
462           sg.setColourScheme(new AnnotationColourGradient(currentAnn,
463                   minColour.getBackground(), maxColour.getBackground(),
464                   selectedThresholdOption));
465           ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
466                   .isSelected());
467         }
468       }
469     }
470     return false;
471   }
472
473 }