JAL-1517 fix copyright for 2.8.2
[jalview.git] / src / jalview / gui / FeatureColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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 java.util.*;
24
25 import java.awt.*;
26 import java.awt.event.*;
27 import javax.swing.*;
28 import javax.swing.border.LineBorder;
29 import javax.swing.event.*;
30
31 import jalview.datamodel.*;
32 import jalview.schemes.*;
33 import jalview.util.MessageManager;
34
35 import java.awt.Dimension;
36
37 public class FeatureColourChooser extends JalviewDialog
38 {
39   // FeatureSettings fs;
40   FeatureRenderer fr;
41
42   private GraduatedColor cs;
43
44   private Object oldcs;
45
46   /**
47    * 
48    * @return the last colour setting selected by user - either oldcs (which may
49    *         be a java.awt.Color) or the new GraduatedColor
50    */
51   public Object getLastColour()
52   {
53     if (cs == null)
54     {
55       return oldcs;
56     }
57     return cs;
58   }
59
60   Hashtable oldgroupColours;
61
62   AlignmentPanel ap;
63
64   boolean adjusting = false;
65
66   private float min;
67
68   private float max;
69
70   String type = null;
71
72   public FeatureColourChooser(FeatureRenderer frender, String type)
73   {
74     this(frender, false, type);
75   }
76
77   public FeatureColourChooser(FeatureRenderer frender, boolean block,
78           String type)
79   {
80     this.fr = frender;
81     this.type = type;
82     ap = fr.ap;
83     initDialogFrame(this, true, block, "Graduated Feature Colour for "
84             + type, 480, 185);
85     // frame.setLayer(JLayeredPane.PALETTE_LAYER);
86     // Desktop.addInternalFrame(frame, "Graduated Feature Colour for "+type,
87     // 480, 145);
88
89     slider.addChangeListener(new ChangeListener()
90     {
91       public void stateChanged(ChangeEvent evt)
92       {
93         if (!adjusting)
94         {
95           thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
96           valueChanged();
97         }
98       }
99     });
100     slider.addMouseListener(new MouseAdapter()
101     {
102       public void mouseReleased(MouseEvent evt)
103       {
104         if (ap != null)
105         {
106           ap.paintAlignment(true);
107         }
108         ;
109       }
110     });
111
112     float mm[] = ((float[][]) fr.minmax.get(type))[0];
113     min = mm[0];
114     max = mm[1];
115     oldcs = fr.featureColours.get(type);
116     if (oldcs instanceof GraduatedColor)
117     {
118       if (((GraduatedColor) oldcs).isAutoScale())
119       {
120         // update the scale
121         cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
122       }
123       else
124       {
125         cs = new GraduatedColor((GraduatedColor) oldcs);
126       }
127     }
128     else
129     {
130       // promote original color to a graduated color
131       Color bl = Color.black;
132       if (oldcs instanceof Color)
133       {
134         bl = (Color) oldcs;
135       }
136       // original colour becomes the maximum colour
137       cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
138       cs.setColourByLabel(false);
139     }
140     minColour.setBackground(oldminColour = cs.getMinColor());
141     maxColour.setBackground(oldmaxColour = cs.getMaxColor());
142     adjusting = true;
143
144     try
145     {
146       jbInit();
147     } catch (Exception ex)
148     {
149     }
150     // update the gui from threshold state
151     thresholdIsMin.setSelected(!cs.isAutoScale());
152     colourByLabel.setSelected(cs.isColourByLabel());
153     if (cs.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
154     {
155       // initialise threshold slider and selector
156       threshold
157               .setSelectedIndex(cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
158                       : 2);
159       slider.setEnabled(true);
160       thresholdValue.setEnabled(true);
161       threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
162               "Threshold", Color.black);
163
164     }
165
166     adjusting = false;
167
168     changeColour();
169     waitForInput();
170   }
171
172   public FeatureColourChooser()
173   {
174     try
175     {
176       jbInit();
177     } catch (Exception ex)
178     {
179       ex.printStackTrace();
180     }
181   }
182
183   private void jbInit() throws Exception
184   {
185
186     minColour.setFont(JvSwingUtils.getLabelFont());
187     minColour.setBorder(BorderFactory.createLineBorder(Color.black));
188     minColour.setPreferredSize(new Dimension(40, 20));
189     minColour.setToolTipText(MessageManager.getString("label.min_colour"));
190     minColour.addMouseListener(new MouseAdapter()
191     {
192       public void mousePressed(MouseEvent e)
193       {
194         if (minColour.isEnabled())
195         {
196           minColour_actionPerformed();
197         }
198       }
199     });
200     maxColour.setFont(JvSwingUtils.getLabelFont());
201     maxColour.setBorder(BorderFactory.createLineBorder(Color.black));
202     maxColour.setPreferredSize(new Dimension(40, 20));
203     maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
204     maxColour.addMouseListener(new MouseAdapter()
205     {
206       public void mousePressed(MouseEvent e)
207       {
208         if (maxColour.isEnabled())
209         {
210           maxColour_actionPerformed();
211         }
212       }
213     });
214     maxColour.setBorder(new LineBorder(Color.black));
215     minText.setText(MessageManager.getString("label.min"));
216     minText.setFont(JvSwingUtils.getLabelFont());
217     maxText.setText(MessageManager.getString("label.max"));
218     maxText.setFont(JvSwingUtils.getLabelFont());
219     this.setLayout(borderLayout1);
220     jPanel2.setLayout(flowLayout1);
221     jPanel1.setBackground(Color.white);
222     jPanel2.setBackground(Color.white);
223     threshold.addActionListener(new ActionListener()
224     {
225       public void actionPerformed(ActionEvent e)
226       {
227         threshold_actionPerformed(e);
228       }
229     });
230     threshold.setToolTipText(MessageManager.getString("label.threshold_feature_display_by_score"));
231     threshold.addItem(MessageManager.getString("label.threshold_feature_no_thereshold")); // index 0
232     threshold.addItem(MessageManager.getString("label.threshold_feature_above_thereshold")); // index 1
233     threshold.addItem(MessageManager.getString("label.threshold_feature_below_thereshold")); // index 2
234     jPanel3.setLayout(flowLayout2);
235     thresholdValue.addActionListener(new ActionListener()
236     {
237       public void actionPerformed(ActionEvent e)
238       {
239         thresholdValue_actionPerformed(e);
240       }
241     });
242     slider.setPaintLabels(false);
243     slider.setPaintTicks(true);
244     slider.setBackground(Color.white);
245     slider.setEnabled(false);
246     slider.setOpaque(false);
247     slider.setPreferredSize(new Dimension(100, 32));
248     slider.setToolTipText(MessageManager.getString("label.adjust_thereshold"));
249     thresholdValue.setEnabled(false);
250     thresholdValue.setColumns(7);
251     jPanel3.setBackground(Color.white);
252     thresholdIsMin.setBackground(Color.white);
253     thresholdIsMin.setText(MessageManager.getString("label.threshold_minmax"));
254     thresholdIsMin
255             .setToolTipText(MessageManager.getString("label.toggle_absolute_relative_display_threshold"));
256     thresholdIsMin.addActionListener(new ActionListener()
257     {
258       public void actionPerformed(ActionEvent actionEvent)
259       {
260         thresholdIsMin_actionPerformed(actionEvent);
261       }
262     });
263     colourByLabel.setBackground(Color.white);
264     colourByLabel.setText(MessageManager.getString("label.colour_by_label"));
265     colourByLabel
266             .setToolTipText(MessageManager.getString("label.display_features_same_type_different_label_using_different_colour"));
267     colourByLabel.addActionListener(new ActionListener()
268     {
269       public void actionPerformed(ActionEvent actionEvent)
270       {
271         colourByLabel_actionPerformed(actionEvent);
272       }
273     });
274     colourPanel.setBackground(Color.white);
275     jPanel1.add(ok);
276     jPanel1.add(cancel);
277     jPanel2.add(colourByLabel, java.awt.BorderLayout.WEST);
278     jPanel2.add(colourPanel, java.awt.BorderLayout.EAST);
279     colourPanel.add(minText);
280     colourPanel.add(minColour);
281     colourPanel.add(maxText);
282     colourPanel.add(maxColour);
283     this.add(jPanel3, java.awt.BorderLayout.CENTER);
284     jPanel3.add(threshold);
285     jPanel3.add(slider);
286     jPanel3.add(thresholdValue);
287     jPanel3.add(thresholdIsMin);
288     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
289     this.add(jPanel2, java.awt.BorderLayout.NORTH);
290   }
291
292   JLabel minText = new JLabel();
293
294   JLabel maxText = new JLabel();
295
296   JPanel minColour = new JPanel();
297
298   JPanel maxColour = new JPanel();
299
300   JPanel colourPanel = new JPanel();
301
302   JPanel jPanel1 = new JPanel();
303
304   JPanel jPanel2 = new JPanel();
305
306   BorderLayout borderLayout1 = new BorderLayout();
307
308   JComboBox threshold = new JComboBox();
309
310   FlowLayout flowLayout1 = new FlowLayout();
311
312   JPanel jPanel3 = new JPanel();
313
314   FlowLayout flowLayout2 = new FlowLayout();
315
316   JSlider slider = new JSlider();
317
318   JTextField thresholdValue = new JTextField(20);
319
320   // TODO implement GUI for tolower flag
321   // JCheckBox toLower = new JCheckBox();
322
323   JCheckBox thresholdIsMin = new JCheckBox();
324
325   JCheckBox colourByLabel = new JCheckBox();
326
327   private GraphLine threshline;
328
329   private Color oldmaxColour;
330
331   private Color oldminColour;
332
333   public void minColour_actionPerformed()
334   {
335     Color col = JColorChooser.showDialog(this,
336             MessageManager.getString("label.select_colour_minimum_value"), minColour.getBackground());
337     if (col != null)
338     {
339       minColour.setBackground(col);
340       minColour.setForeground(col);
341     }
342     minColour.repaint();
343     changeColour();
344   }
345
346   public void maxColour_actionPerformed()
347   {
348     Color col = JColorChooser.showDialog(this,
349             MessageManager.getString("label.select_colour_maximum_value"), maxColour.getBackground());
350     if (col != null)
351     {
352       maxColour.setBackground(col);
353       maxColour.setForeground(col);
354     }
355     maxColour.repaint();
356     changeColour();
357   }
358
359   void changeColour()
360   {
361     // Check if combobox is still adjusting
362     if (adjusting)
363     {
364       return;
365     }
366
367     int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD;
368     if (threshold.getSelectedIndex()==1)
369     {
370       aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
371     }
372     else if (threshold.getSelectedIndex()==2)
373     {
374       aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
375     }
376
377     slider.setEnabled(true);
378     thresholdValue.setEnabled(true);
379
380     GraduatedColor acg;
381     if (cs.isColourByLabel())
382     {
383       acg = new GraduatedColor(oldminColour, oldmaxColour, min, max);
384     }
385     else
386     {
387       acg = new GraduatedColor(oldminColour = minColour.getBackground(),
388               oldmaxColour = maxColour.getBackground(), min, max);
389
390     }
391
392     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
393     {
394       slider.setEnabled(false);
395       thresholdValue.setEnabled(false);
396       thresholdValue.setText("");
397       thresholdIsMin.setEnabled(false);
398     }
399     else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
400             && threshline == null)
401     {
402       // todo visual indication of feature threshold
403       threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
404               "Threshold", Color.black);
405     }
406
407     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
408     {
409       adjusting = true;
410       acg.setThresh(threshline.value);
411
412       float range = max * 1000f - min * 1000f;
413
414       slider.setMinimum((int) (min * 1000));
415       slider.setMaximum((int) (max * 1000));
416       slider.setValue((int) (threshline.value * 1000));
417       thresholdValue.setText(threshline.value + "");
418       slider.setMajorTickSpacing((int) (range / 10f));
419       slider.setEnabled(true);
420       thresholdValue.setEnabled(true);
421       thresholdIsMin.setEnabled(!colourByLabel.isSelected());
422       adjusting = false;
423     }
424
425     acg.setThreshType(aboveThreshold);
426     if (thresholdIsMin.isSelected()
427             && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
428     {
429       acg.setAutoScaled(false);
430       if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
431       {
432         acg = new GraduatedColor(acg, threshline.value, max);
433       }
434       else
435       {
436         acg = new GraduatedColor(acg, min, threshline.value);
437       }
438     }
439     else
440     {
441       acg.setAutoScaled(true);
442     }
443     acg.setColourByLabel(colourByLabel.isSelected());
444     if (acg.isColourByLabel())
445     {
446       maxColour.setEnabled(false);
447       minColour.setEnabled(false);
448       maxColour.setBackground(this.getBackground());
449       maxColour.setForeground(this.getBackground());
450       minColour.setBackground(this.getBackground());
451       minColour.setForeground(this.getBackground());
452
453     }
454     else
455     {
456       maxColour.setEnabled(true);
457       minColour.setEnabled(true);
458       maxColour.setBackground(oldmaxColour);
459       minColour.setBackground(oldminColour);
460       maxColour.setForeground(oldmaxColour);
461       minColour.setForeground(oldminColour);
462     }
463     fr.featureColours.put(type, acg);
464     cs = acg;
465     ap.paintAlignment(false);
466   }
467
468   protected void raiseClosed()
469   {
470     if (this.colourEditor != null)
471     {
472       colourEditor.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
473     }
474   }
475
476   public void okPressed()
477   {
478     changeColour();
479   }
480
481   public void cancelPressed()
482   {
483     reset();
484   }
485
486   void reset()
487   {
488     fr.featureColours.put(type, oldcs);
489     ap.paintAlignment(false);
490     cs = null;
491   }
492
493   public void thresholdCheck_actionPerformed(ActionEvent e)
494   {
495     changeColour();
496   }
497
498   public void annotations_actionPerformed(ActionEvent e)
499   {
500     changeColour();
501   }
502
503   public void threshold_actionPerformed(ActionEvent e)
504   {
505     changeColour();
506   }
507
508   public void thresholdValue_actionPerformed(ActionEvent e)
509   {
510     try
511     {
512       float f = Float.parseFloat(thresholdValue.getText());
513       slider.setValue((int) (f * 1000));
514       threshline.value = f;
515     } catch (NumberFormatException ex)
516     {
517     }
518   }
519
520   public void valueChanged()
521   {
522     threshline.value = (float) slider.getValue() / 1000f;
523     cs.setThresh(threshline.value);
524     changeColour();
525     ap.paintAlignment(false);
526   }
527
528   public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
529   {
530     changeColour();
531   }
532
533   public void colourByLabel_actionPerformed(ActionEvent actionEvent)
534   {
535     changeColour();
536   }
537
538   ActionListener colourEditor = null;
539
540   public void addActionListener(ActionListener graduatedColorEditor)
541   {
542     if (colourEditor != null)
543     {
544       System.err
545               .println("IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
546     }
547     colourEditor = graduatedColorEditor;
548   }
549
550 }