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