default parameter for colours in annotation shading (JAL-234), ensure
[jalview.git] / src / jalview / gui / AnnotationColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import java.util.*;
21
22 import java.awt.*;
23 import java.awt.event.*;
24 import javax.swing.*;
25 import javax.swing.event.*;
26
27 import jalview.bin.Cache;
28 import jalview.datamodel.*;
29 import jalview.schemes.*;
30 import java.awt.Dimension;
31
32 public class AnnotationColourChooser extends JPanel
33 {
34   JInternalFrame frame;
35
36   AlignViewport av;
37
38   AlignmentPanel ap;
39
40   ColourSchemeI oldcs;
41
42   Hashtable oldgroupColours;
43
44   jalview.datamodel.AlignmentAnnotation currentAnnotation;
45
46   boolean adjusting = false;
47
48   public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
49   {
50     oldcs = av.getGlobalColourScheme();
51     if (av.alignment.getGroups() != null)
52     {
53       oldgroupColours = new Hashtable();
54       Vector allGroups = ap.av.alignment.getGroups();
55       SequenceGroup sg;
56       for (int g = 0; g < allGroups.size(); g++)
57       {
58         sg = (SequenceGroup) allGroups.get(g);
59         if (sg.cs != null)
60         {
61           oldgroupColours.put(sg, sg.cs);
62         }
63       }
64     }
65     this.av = av;
66     this.ap = ap;
67     frame = new JInternalFrame();
68     frame.setContentPane(this);
69     frame.setLayer(JLayeredPane.PALETTE_LAYER);
70     Desktop.addInternalFrame(frame, "Colour by Annotation", 480, 145);
71
72     slider.addChangeListener(new ChangeListener()
73     {
74       public void stateChanged(ChangeEvent evt)
75       {
76         if (!adjusting)
77         {
78           thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
79           valueChanged();
80         }
81       }
82     });
83     slider.addMouseListener(new MouseAdapter()
84     {
85       public void mouseReleased(MouseEvent evt)
86       {
87         ap.paintAlignment(true);
88       }
89     });
90
91     if (av.alignment.getAlignmentAnnotation() == null)
92     {
93       return;
94     }
95
96     // Always get default shading from preferences.
97     minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN", Color.orange));
98     maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX", Color.red));
99
100     if (oldcs instanceof AnnotationColourGradient)
101     {
102       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
103       currentColours.setSelected(acg.predefinedColours);
104       if (acg.predefinedColours)
105       {
106         
107       } else {
108         minColour.setBackground(acg.getMinColour());
109         maxColour.setBackground(acg.getMaxColour());
110       }
111     }
112
113     adjusting = true;
114     Vector list = new Vector();
115     int index = 1;
116     for (int i = 0; i < av.alignment.getAlignmentAnnotation().length; i++)
117     {
118       String label = av.alignment.getAlignmentAnnotation()[i].label;
119       if (!list.contains(label))
120         list.addElement(label);
121       else
122         list.addElement(label + "_" + (index++));
123     }
124
125     annotations = new JComboBox(list);
126
127     threshold.addItem("No Threshold");
128     threshold.addItem("Above Threshold");
129     threshold.addItem("Below Threshold");
130
131     if (oldcs instanceof AnnotationColourGradient)
132     {
133       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
134       annotations.setSelectedItem(acg.getAnnotation());
135       switch (acg.getAboveThreshold()) {
136       case AnnotationColourGradient.NO_THRESHOLD:
137           threshold.setSelectedItem("No Threshold");
138         break;
139       case AnnotationColourGradient.ABOVE_THRESHOLD:
140           threshold.setSelectedItem("Above Threshold");
141         break;
142       case AnnotationColourGradient.BELOW_THRESHOLD:
143         threshold.setSelectedItem("Below Threshold");
144         break;
145         default:
146           throw new Error("Implementation error: don't know about threshold setting for current AnnotationColourGradient.");
147       }
148       thresholdIsMin.setSelected(acg.thresholdIsMinMax);
149       thresholdValue.setText(""+acg.getAnnotationThreshold());
150     }
151
152     try
153     {
154       jbInit();
155     } catch (Exception ex)
156     {
157     }
158
159     adjusting = false;
160
161     changeColour();
162     validate();
163
164   }
165
166   public AnnotationColourChooser()
167   {
168     try
169     {
170       jbInit();
171     } catch (Exception ex)
172     {
173       ex.printStackTrace();
174     }
175   }
176
177   private void jbInit() throws Exception
178   {
179     minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
180     minColour.setBorder(BorderFactory.createEtchedBorder());
181     minColour.setPreferredSize(new Dimension(40, 20));
182     minColour.setToolTipText("Minimum Colour");
183     minColour.addMouseListener(new MouseAdapter()
184     {
185       public void mousePressed(MouseEvent e)
186       {
187         if (minColour.isEnabled())
188         {
189           minColour_actionPerformed();
190         }
191       }
192     });
193     maxColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
194     maxColour.setBorder(BorderFactory.createEtchedBorder());
195     maxColour.setPreferredSize(new Dimension(40, 20));
196     maxColour.setToolTipText("Maximum Colour");
197     maxColour.addMouseListener(new MouseAdapter()
198     {
199       public void mousePressed(MouseEvent e)
200       {
201         if (maxColour.isEnabled())
202         {
203           maxColour_actionPerformed();
204         }
205       }
206     });
207     ok.setOpaque(false);
208     ok.setText("OK");
209     ok.addActionListener(new ActionListener()
210     {
211       public void actionPerformed(ActionEvent e)
212       {
213         ok_actionPerformed(e);
214       }
215     });
216     cancel.setOpaque(false);
217     cancel.setText("Cancel");
218     cancel.addActionListener(new ActionListener()
219     {
220       public void actionPerformed(ActionEvent e)
221       {
222         cancel_actionPerformed(e);
223       }
224     });
225     this.setLayout(borderLayout1);
226     jPanel2.setLayout(flowLayout1);
227     annotations.addActionListener(new ActionListener()
228     {
229       public void actionPerformed(ActionEvent e)
230       {
231         annotations_actionPerformed(e);
232       }
233     });
234     jPanel1.setBackground(Color.white);
235     jPanel2.setBackground(Color.white);
236     threshold.addActionListener(new ActionListener()
237     {
238       public void actionPerformed(ActionEvent e)
239       {
240         threshold_actionPerformed(e);
241       }
242     });
243     jPanel3.setLayout(flowLayout2);
244     thresholdValue.addActionListener(new ActionListener()
245     {
246       public void actionPerformed(ActionEvent e)
247       {
248         thresholdValue_actionPerformed(e);
249       }
250     });
251     slider.setPaintLabels(false);
252     slider.setPaintTicks(true);
253     slider.setBackground(Color.white);
254     slider.setEnabled(false);
255     slider.setOpaque(false);
256     slider.setPreferredSize(new Dimension(100, 32));
257     thresholdValue.setEnabled(false);
258     thresholdValue.setColumns(7);
259     jPanel3.setBackground(Color.white);
260     currentColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
261     currentColours.setOpaque(false);
262     currentColours.setText("Use Original Colours");
263     currentColours.addActionListener(new ActionListener()
264     {
265       public void actionPerformed(ActionEvent e)
266       {
267         currentColours_actionPerformed(e);
268       }
269     });
270     thresholdIsMin.setBackground(Color.white);
271     thresholdIsMin.setText("Threshold is Min/Max");
272     thresholdIsMin.addActionListener(new ActionListener()
273     {
274       public void actionPerformed(ActionEvent actionEvent)
275       {
276         thresholdIsMin_actionPerformed(actionEvent);
277       }
278     });
279     jPanel1.add(ok);
280     jPanel1.add(cancel);
281     jPanel2.add(annotations);
282     jPanel2.add(currentColours);
283     jPanel2.add(minColour);
284     jPanel2.add(maxColour);
285     this.add(jPanel3, java.awt.BorderLayout.CENTER);
286     jPanel3.add(threshold);
287     jPanel3.add(slider);
288     jPanel3.add(thresholdValue);
289     jPanel3.add(thresholdIsMin);
290     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
291     this.add(jPanel2, java.awt.BorderLayout.NORTH);
292   }
293
294   JComboBox annotations;
295
296   JPanel minColour = new JPanel();
297
298   JPanel maxColour = new JPanel();
299
300   JButton ok = new JButton();
301
302   JButton cancel = new JButton();
303
304   JPanel jPanel1 = new JPanel();
305
306   JPanel jPanel2 = new JPanel();
307
308   BorderLayout borderLayout1 = new BorderLayout();
309
310   JComboBox threshold = new JComboBox();
311
312   FlowLayout flowLayout1 = new FlowLayout();
313
314   JPanel jPanel3 = new JPanel();
315
316   FlowLayout flowLayout2 = new FlowLayout();
317
318   JSlider slider = new JSlider();
319
320   JTextField thresholdValue = new JTextField(20);
321
322   JCheckBox currentColours = new JCheckBox();
323
324   JCheckBox thresholdIsMin = new JCheckBox();
325
326   public void minColour_actionPerformed()
327   {
328     Color col = JColorChooser.showDialog(this,
329             "Select Colour for Minimum Value", minColour.getBackground());
330     if (col != null)
331     {
332       minColour.setBackground(col);
333     }
334     minColour.repaint();
335     changeColour();
336   }
337
338   public void maxColour_actionPerformed()
339   {
340     Color col = JColorChooser.showDialog(this,
341             "Select Colour for Maximum Value", maxColour.getBackground());
342     if (col != null)
343     {
344       maxColour.setBackground(col);
345     }
346     maxColour.repaint();
347     changeColour();
348   }
349
350   void changeColour()
351   {
352     // Check if combobox is still adjusting
353     if (adjusting)
354     {
355       return;
356     }
357
358     currentAnnotation = av.alignment.getAlignmentAnnotation()[annotations
359             .getSelectedIndex()];
360
361     int aboveThreshold = -1;
362     if (threshold.getSelectedItem().equals("Above Threshold"))
363     {
364       aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
365     }
366     else if (threshold.getSelectedItem().equals("Below Threshold"))
367     {
368       aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
369     }
370
371     slider.setEnabled(true);
372     thresholdValue.setEnabled(true);
373
374     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
375     {
376       slider.setEnabled(false);
377       thresholdValue.setEnabled(false);
378       thresholdValue.setText("");
379     }
380     else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
381             && currentAnnotation.threshold == null)
382     {
383       currentAnnotation
384               .setThreshold(new jalview.datamodel.GraphLine(
385                       (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
386                       "Threshold", Color.black));
387     }
388
389     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
390     {
391       adjusting = true;
392       float range = currentAnnotation.graphMax * 1000
393               - currentAnnotation.graphMin * 1000;
394
395       slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
396       slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
397       slider.setValue((int) (currentAnnotation.threshold.value * 1000));
398       thresholdValue.setText(currentAnnotation.threshold.value + "");
399       slider.setMajorTickSpacing((int) (range / 10f));
400       slider.setEnabled(true);
401       thresholdValue.setEnabled(true);
402       adjusting = false;
403     }
404
405     AnnotationColourGradient acg = null;
406     if (currentColours.isSelected())
407     {
408       acg = new AnnotationColourGradient(currentAnnotation,
409               av.getGlobalColourScheme(), aboveThreshold);
410     }
411     else
412     {
413       acg = new AnnotationColourGradient(currentAnnotation,
414               minColour.getBackground(), maxColour.getBackground(),
415               aboveThreshold);
416     }
417
418     if (currentAnnotation.graphMin == 0f
419             && currentAnnotation.graphMax == 0f)
420     {
421       acg.predefinedColours = true;
422     }
423
424     acg.thresholdIsMinMax = thresholdIsMin.isSelected();
425
426     av.setGlobalColourScheme(acg);
427
428     if (av.alignment.getGroups() != null)
429     {
430       Vector allGroups = ap.av.alignment.getGroups();
431       SequenceGroup sg;
432       for (int g = 0; g < allGroups.size(); g++)
433       {
434         sg = (SequenceGroup) allGroups.get(g);
435
436         if (sg.cs == null)
437         {
438           continue;
439         }
440
441         if (currentColours.isSelected())
442         {
443           sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
444                   aboveThreshold);
445         }
446         else
447         {
448           sg.cs = new AnnotationColourGradient(currentAnnotation,
449                   minColour.getBackground(), maxColour.getBackground(),
450                   aboveThreshold);
451         }
452
453       }
454     }
455     // ensure all associated views (overviews, structures, etc) are notified of updated colours.
456     ap.paintAlignment(true);
457   }
458
459   public void ok_actionPerformed(ActionEvent e)
460   {
461     changeColour();
462     try
463     {
464       frame.setClosed(true);
465     } catch (Exception ex)
466     {
467     }
468   }
469
470   public void cancel_actionPerformed(ActionEvent e)
471   {
472     reset();
473     try
474     {
475       frame.setClosed(true);
476     } catch (Exception ex)
477     {
478     }
479   }
480
481   void reset()
482   {
483     av.setGlobalColourScheme(oldcs);
484     if (av.alignment.getGroups() != null)
485     {
486       Vector allGroups = ap.av.alignment.getGroups();
487       SequenceGroup sg;
488       for (int g = 0; g < allGroups.size(); g++)
489       {
490         sg = (SequenceGroup) allGroups.get(g);
491         sg.cs = (ColourSchemeI) oldgroupColours.get(sg);
492       }
493     }
494   }
495
496   public void thresholdCheck_actionPerformed(ActionEvent e)
497   {
498     changeColour();
499   }
500
501   public void annotations_actionPerformed(ActionEvent e)
502   {
503     changeColour();
504   }
505
506   public void threshold_actionPerformed(ActionEvent e)
507   {
508     changeColour();
509   }
510
511   public void thresholdValue_actionPerformed(ActionEvent e)
512   {
513     try
514     {
515       float f = Float.parseFloat(thresholdValue.getText());
516       slider.setValue((int) (f * 1000));
517     } catch (NumberFormatException ex)
518     {
519     }
520   }
521
522   public void valueChanged()
523   {
524     if (currentColours.isSelected()
525             && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
526     {
527       changeColour();
528     }
529
530     currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
531     ap.paintAlignment(false);
532   }
533
534   public void currentColours_actionPerformed(ActionEvent e)
535   {
536     if (currentColours.isSelected())
537     {
538       reset();
539     }
540
541     maxColour.setEnabled(!currentColours.isSelected());
542     minColour.setEnabled(!currentColours.isSelected());
543
544     changeColour();
545   }
546
547   public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
548   {
549     changeColour();
550   }
551
552 }