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