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