JAL-1620 version bump and release notes
[jalview.git] / src / jalview / appletgui / AnnotationColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
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.appletgui;
22
23 import java.util.*;
24
25 import java.awt.*;
26 import java.awt.event.*;
27
28 import jalview.datamodel.*;
29 import jalview.schemes.*;
30 import jalview.util.MessageManager;
31
32 public class AnnotationColourChooser extends Panel implements
33         ActionListener, AdjustmentListener, ItemListener, MouseListener
34 {
35   Frame frame;
36
37   AlignViewport av;
38
39   AlignmentPanel ap;
40
41   ColourSchemeI oldcs;
42
43   Hashtable oldgroupColours;
44
45   jalview.datamodel.AlignmentAnnotation currentAnnotation;
46
47   boolean adjusting = false;
48
49   public AnnotationColourChooser(AlignViewport av, AlignmentPanel ap)
50   {
51     try
52     {
53       jbInit();
54     } catch (Exception ex)
55     {
56     }
57
58     oldcs = av.getGlobalColourScheme();
59     if (av.getAlignment().getGroups() != null)
60     {
61       oldgroupColours = new Hashtable();
62       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
63       {
64         if (sg.cs != null)
65         {
66           oldgroupColours.put(sg, sg.cs);
67         }
68         else
69         {
70           oldgroupColours.put(sg, "null");
71         }
72       }
73     }
74     this.av = av;
75     this.ap = ap;
76
77     slider.addAdjustmentListener(this);
78     slider.addMouseListener(this);
79
80     if (av.getAlignment().getAlignmentAnnotation() == null)
81     {
82       return;
83     }
84
85     setDefaultMinMax();
86
87     adjusting = true;
88     if (oldcs instanceof AnnotationColourGradient)
89     {
90       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
91       currentColours.setState(acg.isPredefinedColours()
92               || acg.getBaseColour() != null);
93       if (!acg.isPredefinedColours() && acg.getBaseColour() == null)
94       {
95         minColour.setBackground(acg.getMinColour());
96         maxColour.setBackground(acg.getMaxColour());
97       }
98       // seqAssociated.setState(acg.isSeqAssociated());
99     }
100
101     Vector list = new Vector();
102     int index = 1;
103     for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
104     {
105       String label = av.getAlignment().getAlignmentAnnotation()[i].label;
106       if (!list.contains(label))
107         list.addElement(label);
108       else
109         list.addElement(label + "_" + (index++));
110     }
111
112     for (int i = 0; i < list.size(); i++)
113     {
114       annotations.addItem(list.elementAt(i).toString());
115     }
116
117     threshold.addItem(MessageManager
118             .getString("label.threshold_feature_no_thereshold"));
119     threshold.addItem(MessageManager
120             .getString("label.threshold_feature_above_thereshold"));
121     threshold.addItem(MessageManager
122             .getString("label.threshold_feature_below_thereshold"));
123
124     if (oldcs instanceof AnnotationColourGradient)
125     {
126       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
127       annotations.select(acg.getAnnotation());
128       switch (acg.getAboveThreshold())
129       {
130       case AnnotationColourGradient.NO_THRESHOLD:
131         threshold.select(0);
132         break;
133       case AnnotationColourGradient.ABOVE_THRESHOLD:
134         threshold.select(1);
135         break;
136       case AnnotationColourGradient.BELOW_THRESHOLD:
137         threshold.select(1);
138         break;
139       default:
140         throw new Error(MessageManager.getString("error.implementation_error_dont_know_thereshold_annotationcolourgradient"));
141       }
142       thresholdIsMin.setState(acg.thresholdIsMinMax);
143       thresholdValue.setText("" + acg.getAnnotationThreshold());
144     }
145
146     adjusting = false;
147
148     changeColour();
149
150     frame = new Frame();
151     frame.add(this);
152     jalview.bin.JalviewLite.addFrame(frame,
153             MessageManager.getString("label.colour_by_annotation"), 560,
154             175);
155     validate();
156   }
157
158   private void setDefaultMinMax()
159   {
160     minColour.setBackground(av.applet.getDefaultColourParameter(
161             "ANNOTATIONCOLOUR_MIN", Color.orange));
162     maxColour.setBackground(av.applet.getDefaultColourParameter(
163             "ANNOTATIONCOLOUR_MAX", Color.red));
164
165   }
166
167   public AnnotationColourChooser()
168   {
169     try
170     {
171       jbInit();
172     } catch (Exception ex)
173     {
174       ex.printStackTrace();
175     }
176   }
177
178   private void jbInit() throws Exception
179   {
180     minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
181     minColour.setLabel(MessageManager.getString("label.min_colour"));
182     minColour.addActionListener(this);
183
184     maxColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
185     maxColour.setLabel(MessageManager.getString("label.max_colour"));
186     maxColour.addActionListener(this);
187
188     thresholdIsMin.addItemListener(this);
189     ok.setLabel(MessageManager.getString("action.ok"));
190     ok.addActionListener(this);
191
192     cancel.setLabel(MessageManager.getString("action.cancel"));
193     cancel.addActionListener(this);
194
195     defColours.setLabel(MessageManager.getString("action.set_defaults"));
196     defColours.addActionListener(this);
197
198     annotations.addItemListener(this);
199
200     thresholdValue.addActionListener(this);
201     slider.setBackground(Color.white);
202     slider.setPreferredSize(new Dimension(193, 21));
203     slider.setEnabled(false);
204     thresholdValue.setPreferredSize(new Dimension(79, 22));
205     thresholdValue.setEnabled(false);
206     thresholdValue.setColumns(5);
207     currentColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
208     currentColours.setLabel(MessageManager
209             .getString("label.use_original_colours"));
210     currentColours.addItemListener(this);
211
212     thresholdIsMin.setBackground(Color.white);
213     thresholdIsMin.setLabel(MessageManager
214             .getString("label.threshold_minmax"));
215
216     this.setLayout(borderLayout1);
217
218     jPanel1.setBackground(Color.white);
219
220     jPanel2.setLayout(new FlowLayout());
221     jPanel2.setBackground(Color.white);
222     threshold.addItemListener(this);
223     jPanel3.setLayout(new FlowLayout());
224     jPanel3.setBackground(Color.white);
225     Panel jPanel4 = new Panel();
226     jPanel4.setLayout(new BorderLayout());
227     jPanel4.setBackground(Color.white);
228
229     jPanel1.add(ok);
230     jPanel1.add(cancel);
231
232     jPanel2.add(annotations);
233     jPanel2.add(currentColours);
234     jPanel2.add(minColour);
235     jPanel2.add(maxColour);
236
237     jPanel4.add(thresholdIsMin, BorderLayout.WEST);
238     jPanel4.add(slider, BorderLayout.CENTER);
239     jPanel4.add(thresholdValue, BorderLayout.EAST);
240
241     Panel jPanel34 = new Panel();
242     jPanel34.setLayout(new BorderLayout());
243     jPanel34.setBackground(Color.white);
244     jPanel34.add(jPanel2, BorderLayout.NORTH);
245     jPanel34.add(threshold, BorderLayout.WEST);
246     jPanel3.add(defColours);
247     jPanel34.add(jPanel3, BorderLayout.EAST);
248     jPanel34.add(jPanel4, BorderLayout.SOUTH);
249
250     this.add(jPanel34, java.awt.BorderLayout.CENTER);
251     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
252
253   }
254
255   Choice annotations = new Choice();
256
257   Button minColour = new Button();
258
259   Button maxColour = new Button();
260
261   Button ok = new Button();
262
263   Button cancel = new Button();
264
265   Button defColours = new Button();
266
267   Panel jPanel1 = new Panel();
268
269   Panel jPanel2 = new Panel();
270
271   Choice threshold = new Choice();
272
273   FlowLayout flowLayout1 = new FlowLayout();
274
275   Panel jPanel3 = new Panel();
276
277   Scrollbar slider = new Scrollbar(Scrollbar.HORIZONTAL);
278
279   TextField thresholdValue = new TextField(20);
280
281   Checkbox currentColours = new Checkbox();
282
283   BorderLayout borderLayout1 = new BorderLayout();
284
285   Checkbox thresholdIsMin = new Checkbox();
286
287   public void actionPerformed(ActionEvent evt)
288   {
289     if (evt.getSource() == thresholdValue)
290     {
291       try
292       {
293         float f = new Float(thresholdValue.getText()).floatValue();
294         slider.setValue((int) (f * 1000));
295         adjustmentValueChanged(null);
296       } catch (NumberFormatException ex)
297       {
298       }
299     }
300     else if (evt.getSource() == minColour)
301     {
302       minColour_actionPerformed(null);
303     }
304     else if (evt.getSource() == maxColour)
305     {
306       maxColour_actionPerformed(null);
307     }
308     else if (evt.getSource() == defColours)
309     {
310       defColour_actionPerformed();
311     }
312     else if (evt.getSource() == ok)
313     {
314       changeColour();
315       frame.setVisible(false);
316     }
317     else if (evt.getSource() == cancel)
318     {
319       reset();
320       ap.paintAlignment(true);
321       frame.setVisible(false);
322     }
323
324     else
325     {
326       changeColour();
327     }
328   }
329
330   public void itemStateChanged(ItemEvent evt)
331   {
332     if (evt.getSource() == currentColours)
333     {
334       if (currentColours.getState())
335       {
336         reset();
337       }
338
339       maxColour.setEnabled(!currentColours.getState());
340       minColour.setEnabled(!currentColours.getState());
341
342     }
343
344     changeColour();
345   }
346
347   public void adjustmentValueChanged(AdjustmentEvent evt)
348   {
349     if (!adjusting)
350     {
351       thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
352       if (currentColours.getState()
353               && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
354       {
355         changeColour();
356       }
357
358       currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
359       ap.paintAlignment(false);
360     }
361   }
362
363   public void minColour_actionPerformed(Color newCol)
364   {
365     if (newCol != null)
366     {
367       minColour.setBackground(newCol);
368       minColour.repaint();
369       changeColour();
370     }
371     else
372     {
373       new UserDefinedColours(this, "Min Colour", minColour.getBackground());
374     }
375
376   }
377
378   public void maxColour_actionPerformed(Color newCol)
379   {
380     if (newCol != null)
381     {
382       maxColour.setBackground(newCol);
383       maxColour.repaint();
384       changeColour();
385     }
386     else
387     {
388       new UserDefinedColours(this, "Max Colour", maxColour.getBackground());
389     }
390   }
391
392   public void defColour_actionPerformed()
393   {
394     setDefaultMinMax();
395     minColour.repaint();
396     maxColour.repaint();
397     changeColour();
398   }
399
400   void changeColour()
401   {
402     // Check if combobox is still adjusting
403     if (adjusting)
404     {
405       return;
406     }
407
408     currentAnnotation = av.getAlignment().getAlignmentAnnotation()[annotations
409             .getSelectedIndex()];
410
411     int aboveThreshold = -1;
412     if (threshold.getSelectedIndex() == 1)
413     {
414       aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
415     }
416     else if (threshold.getSelectedIndex() == 2)
417     {
418       aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
419     }
420
421     slider.setEnabled(true);
422     thresholdValue.setEnabled(true);
423     thresholdIsMin.setEnabled(true);
424
425     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
426     {
427       slider.setEnabled(false);
428       thresholdValue.setEnabled(false);
429       thresholdIsMin.setEnabled(false);
430       thresholdValue.setText("");
431     }
432     else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
433             && currentAnnotation.threshold == null)
434     {
435       currentAnnotation
436               .setThreshold(new jalview.datamodel.GraphLine(
437                       (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
438                       "Threshold", Color.black));
439     }
440
441     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
442     {
443       adjusting = true;
444
445       slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
446       slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
447       slider.setValue((int) (currentAnnotation.threshold.value * 1000));
448       thresholdValue.setText(currentAnnotation.threshold.value + "");
449       slider.setEnabled(true);
450       thresholdValue.setEnabled(true);
451       adjusting = false;
452     }
453
454     AnnotationColourGradient acg = null;
455     if (currentColours.getState())
456     {
457       acg = new AnnotationColourGradient(currentAnnotation,
458               av.getGlobalColourScheme(), aboveThreshold);
459     }
460     else
461     {
462       acg = new AnnotationColourGradient(currentAnnotation,
463               minColour.getBackground(), maxColour.getBackground(),
464               aboveThreshold);
465     }
466
467     if (currentAnnotation.graphMin == 0f
468             && currentAnnotation.graphMax == 0f)
469     {
470       acg.setPredefinedColours(true);
471     }
472
473     acg.thresholdIsMinMax = thresholdIsMin.getState();
474
475     av.setGlobalColourScheme(acg);
476
477     // TODO: per group colour propagation not always desired
478     if (av.getAlignment().getGroups() != null)
479     {
480       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
481       {
482
483         if (sg.cs == null)
484         {
485           continue;
486         }
487
488         if (currentColours.getState())
489         {
490           sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
491                   aboveThreshold);
492         }
493         else
494         {
495           sg.cs = new AnnotationColourGradient(currentAnnotation,
496                   minColour.getBackground(), maxColour.getBackground(),
497                   aboveThreshold);
498         }
499
500       }
501     }
502
503     // update colours in linked windows
504     ap.alignmentChanged();
505     ap.paintAlignment(true);
506   }
507
508   void reset()
509   {
510     av.setGlobalColourScheme(oldcs);
511     if (av.getAlignment().getGroups() != null)
512     {
513       for (SequenceGroup sg : ap.av.getAlignment().getGroups())
514       {
515         Object cs = oldgroupColours.get(sg);
516         if (cs instanceof ColourSchemeI)
517         {
518           sg.cs = (ColourSchemeI) cs;
519         }
520         else
521         {
522           // probably the "null" string we set it to if it was null originally.
523           sg.cs = null;
524         }
525       }
526     }
527     ap.paintAlignment(true);
528
529   }
530
531   public void mouseClicked(MouseEvent evt)
532   {
533   }
534
535   public void mousePressed(MouseEvent evt)
536   {
537   }
538
539   public void mouseReleased(MouseEvent evt)
540   {
541     ap.paintAlignment(true);
542   }
543
544   public void mouseEntered(MouseEvent evt)
545   {
546   }
547
548   public void mouseExited(MouseEvent evt)
549   {
550   }
551
552 }