bugfix to avoid null pointer exceptions being raised for groups with no colourscheme...
[jalview.git] / src / jalview / appletgui / AnnotationColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.appletgui;
20
21 import java.util.*;
22
23 import java.awt.*;
24 import java.awt.event.*;
25
26 import jalview.datamodel.*;
27 import jalview.schemes.*;
28 import java.awt.Rectangle;
29
30 public class AnnotationColourChooser
31     extends Panel implements ActionListener,
32     AdjustmentListener, ItemListener, MouseListener
33 {
34   Frame frame;
35   AlignViewport av;
36   AlignmentPanel ap;
37   ColourSchemeI oldcs;
38   Hashtable oldgroupColours;
39   jalview.datamodel.AlignmentAnnotation currentAnnotation;
40   boolean adjusting = false;
41
42   public AnnotationColourChooser(AlignViewport av, AlignmentPanel ap)
43   {
44     try
45     {
46       jbInit();
47     }
48     catch (Exception ex)
49     {}
50
51     oldcs = av.getGlobalColourScheme();
52     if (av.alignment.getGroups() != null)
53     {
54       oldgroupColours = new Hashtable();
55       Vector allGroups = ap.av.alignment.getGroups();
56       SequenceGroup sg;
57       for (int g = 0; g < allGroups.size(); g++)
58       {
59         sg = (SequenceGroup) allGroups.elementAt(g);
60         if (sg.cs!=null)
61         {
62             oldgroupColours.put(sg, sg.cs);
63         } else {
64           oldgroupColours.put(sg, "null");
65         }
66       }
67     }
68     this.av = av;
69     this.ap = ap;
70
71     slider.addAdjustmentListener(this);
72     slider.addMouseListener(this);
73
74     if (av.alignment.getAlignmentAnnotation() == null)
75     {
76       return;
77     }
78
79     if (oldcs instanceof AnnotationColourGradient)
80     {
81       AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
82       minColour.setBackground(acg.getMinColour());
83       maxColour.setBackground(acg.getMaxColour());
84     }
85     else
86     {
87       minColour.setBackground(Color.orange);
88       maxColour.setBackground(Color.red);
89     }
90
91     adjusting = true;
92
93     Vector list = new Vector();
94     int index = 1;
95     for (int i = 0; i < av.alignment.getAlignmentAnnotation().length; i++)
96     {
97       String label = av.alignment.getAlignmentAnnotation()[i].label;
98       if (!list.contains(label))
99         list.addElement(label);
100       else
101         list.addElement(label+"_"+(index++));
102     }
103
104     for (int i = 0; i < list.size(); i++)
105     {
106         annotations.addItem(list.elementAt(i).toString());
107     }
108
109     threshold.addItem("No Threshold");
110     threshold.addItem("Above Threshold");
111     threshold.addItem("Below Threshold");
112
113     adjusting = false;
114
115     changeColour();
116
117     frame = new Frame();
118     frame.add(this);
119     jalview.bin.JalviewLite.addFrame(frame, "Colour by Annotation", 480, 145);
120     validate();
121   }
122
123   public AnnotationColourChooser()
124   {
125     try
126     {
127       jbInit();
128     }
129     catch (Exception ex)
130     {
131       ex.printStackTrace();
132     }
133   }
134
135   private void jbInit()
136       throws Exception
137   {
138     minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
139     minColour.setLabel("Min Colour");
140     minColour.addActionListener(this);
141
142     maxColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
143     maxColour.setLabel("Max Colour");
144     maxColour.addActionListener(this);
145
146     thresholdIsMin.addItemListener(this);
147     ok.setLabel("OK");
148     ok.addActionListener(this);
149
150     cancel.setLabel("Cancel");
151     cancel.addActionListener(this);
152
153     this.setLayout(borderLayout1);
154     jPanel2.setLayout(flowLayout1);
155     annotations.addItemListener(this);
156
157     jPanel1.setBackground(Color.white);
158     jPanel2.setBackground(Color.white);
159     threshold.addItemListener(this);
160     jPanel3.setLayout(null);
161     thresholdValue.addActionListener(this);
162
163     slider.setBackground(Color.white);
164     slider.setEnabled(false);
165     slider.setBounds(new Rectangle(153, 3, 93, 21));
166     thresholdValue.setEnabled(false);
167     thresholdValue.setBounds(new Rectangle(248, 2, 79, 22));
168     thresholdValue.setColumns(5);
169     jPanel3.setBackground(Color.white);
170     currentColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
171     currentColours.setLabel("Use Original Colours");
172     currentColours.addItemListener(this);
173
174     threshold.setBounds(new Rectangle(11, 3, 139, 22));
175     thresholdIsMin.setBackground(Color.white);
176     thresholdIsMin.setLabel("Threshold is min/max");
177     thresholdIsMin.setBounds(new Rectangle(328, 3, 135, 23));
178     jPanel1.add(ok);
179     jPanel1.add(cancel);
180     jPanel2.add(annotations);
181     jPanel2.add(currentColours);
182     jPanel2.add(minColour);
183     jPanel2.add(maxColour);
184     jPanel3.add(threshold);
185     jPanel3.add(slider);
186     jPanel3.add(thresholdValue);
187     jPanel3.add(thresholdIsMin);
188     this.add(jPanel2, java.awt.BorderLayout.NORTH);
189     this.add(jPanel3, java.awt.BorderLayout.CENTER);
190     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
191   }
192
193   Choice annotations = new Choice();
194   Button minColour = new Button();
195   Button maxColour = new Button();
196   Button ok = new Button();
197   Button cancel = new Button();
198   Panel jPanel1 = new Panel();
199   Panel jPanel2 = new Panel();
200   Choice threshold = new Choice();
201   FlowLayout flowLayout1 = new FlowLayout();
202   Panel jPanel3 = new Panel();
203   Scrollbar slider = new Scrollbar(Scrollbar.HORIZONTAL);
204   TextField thresholdValue = new TextField(20);
205   Checkbox currentColours = new Checkbox();
206   BorderLayout borderLayout1 = new BorderLayout();
207   Checkbox thresholdIsMin = new Checkbox();
208
209   public void actionPerformed(ActionEvent evt)
210   {
211     if (evt.getSource() == thresholdValue)
212     {
213       try
214       {
215         float f = new Float(thresholdValue.getText()).floatValue();
216         slider.setValue( (int) (f * 1000));
217         adjustmentValueChanged(null);
218       }
219       catch (NumberFormatException ex)
220       {}
221     }
222     else if (evt.getSource() == minColour)
223     {
224       minColour_actionPerformed(null);
225     }
226     else if (evt.getSource() == maxColour)
227     {
228       maxColour_actionPerformed(null);
229     }
230
231     else if (evt.getSource() == ok)
232     {
233       changeColour();
234       frame.setVisible(false);
235     }
236     else if (evt.getSource() == cancel)
237     {
238       reset();
239       ap.paintAlignment(true);
240       frame.setVisible(false);
241     }
242
243     else
244     {
245       changeColour();
246     }
247   }
248
249   public void itemStateChanged(ItemEvent evt)
250   {
251     if (evt.getSource() == currentColours)
252     {
253       if (currentColours.getState())
254       {
255         reset();
256       }
257
258       maxColour.setEnabled(!currentColours.getState());
259       minColour.setEnabled(!currentColours.getState());
260
261     }
262
263     changeColour();
264   }
265
266   public void adjustmentValueChanged(AdjustmentEvent evt)
267   {
268     if (!adjusting)
269     {
270       thresholdValue.setText( ( (float) slider.getValue() / 1000f) + "");
271       if (currentColours.getState()
272           && ! (av.getGlobalColourScheme() instanceof AnnotationColourGradient))
273       {
274         changeColour();
275       }
276
277       currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
278       ap.paintAlignment(false);
279     }
280   }
281
282   public void minColour_actionPerformed(Color newCol)
283   {
284     if (newCol != null)
285     {
286       minColour.setBackground(newCol);
287       minColour.repaint();
288       changeColour();
289     }
290     else
291     {
292       new UserDefinedColours(this, "Min Colour",
293                              minColour.getBackground());
294     }
295
296   }
297
298   public void maxColour_actionPerformed(Color newCol)
299   {
300     if (newCol != null)
301     {
302       maxColour.setBackground(newCol);
303       maxColour.repaint();
304       changeColour();
305     }
306     else
307     {
308       new UserDefinedColours(this, "Max Colour",
309                              maxColour.getBackground());
310     }
311   }
312
313   void changeColour()
314   {
315     // Check if combobox is still adjusting
316     if (adjusting)
317     {
318       return;
319     }
320
321
322     currentAnnotation = av.alignment.getAlignmentAnnotation()
323         [annotations.getSelectedIndex()];
324
325     int aboveThreshold = -1;
326     if (threshold.getSelectedItem().equals("Above Threshold"))
327     {
328       aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
329     }
330     else if (threshold.getSelectedItem().equals("Below Threshold"))
331     {
332       aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
333     }
334
335     slider.setEnabled(true);
336     thresholdValue.setEnabled(true);
337
338     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
339     {
340       slider.setEnabled(false);
341       thresholdValue.setEnabled(false);
342       thresholdValue.setText("");
343     }
344     else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD &&
345              currentAnnotation.threshold == null)
346     {
347       currentAnnotation.setThreshold(new jalview.datamodel.GraphLine
348                                      ( (currentAnnotation.graphMax -
349                                         currentAnnotation.graphMin) / 2f,
350                                       "Threshold",
351                                       Color.black));
352     }
353
354     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
355     {
356       adjusting = true;
357
358       slider.setMinimum( (int) (currentAnnotation.graphMin * 1000));
359       slider.setMaximum( (int) (currentAnnotation.graphMax * 1000));
360       slider.setValue( (int) (currentAnnotation.threshold.value * 1000));
361       thresholdValue.setText(currentAnnotation.threshold.value + "");
362       slider.setEnabled(true);
363       thresholdValue.setEnabled(true);
364       adjusting = false;
365     }
366
367     AnnotationColourGradient acg = null;
368     if (currentColours.getState())
369     {
370       acg = new AnnotationColourGradient(
371           currentAnnotation,
372           av.getGlobalColourScheme(), aboveThreshold);
373     }
374     else
375     {
376       acg =
377           new AnnotationColourGradient(
378               currentAnnotation,
379               minColour.getBackground(),
380               maxColour.getBackground(),
381               aboveThreshold);
382     }
383
384     if (currentAnnotation.graphMin == 0f && currentAnnotation.graphMax == 0f)
385     {
386       acg.predefinedColours = true;
387     }
388
389     acg.thresholdIsMinMax = thresholdIsMin.getState();
390
391     av.setGlobalColourScheme(acg);
392
393     if (av.alignment.getGroups() != null)
394     {
395       Vector allGroups = ap.av.alignment.getGroups();
396       SequenceGroup sg;
397       for (int g = 0; g < allGroups.size(); g++)
398       {
399         sg = (SequenceGroup) allGroups.elementAt(g);
400
401         if (sg.cs == null)
402         {
403           continue;
404         }
405
406         if (currentColours.getState())
407         {
408           sg.cs = new AnnotationColourGradient(
409               currentAnnotation,
410               sg.cs, aboveThreshold);
411         }
412         else
413         {
414           sg.cs = new AnnotationColourGradient(
415               currentAnnotation,
416               minColour.getBackground(),
417               maxColour.getBackground(),
418               aboveThreshold);
419         }
420
421       }
422     }
423
424     ap.paintAlignment(false);
425   }
426
427   void reset()
428   {
429     av.setGlobalColourScheme(oldcs);
430     if (av.alignment.getGroups() != null)
431     {
432       Vector allGroups = ap.av.alignment.getGroups();
433       SequenceGroup sg;
434       for (int g = 0; g < allGroups.size(); g++)
435       {
436         sg = (SequenceGroup) allGroups.elementAt(g);
437         Object cs = oldgroupColours.get(sg);
438         if (cs instanceof ColourSchemeI)
439         {
440           sg.cs = (ColourSchemeI) cs; 
441         } else {
442           // probably the "null" string we set it to if it was null originally.
443           sg.cs = null;
444         }
445       }
446     }
447     ap.paintAlignment(true);
448
449   }
450
451   public void mouseClicked(MouseEvent evt){}
452   public void mousePressed(MouseEvent evt){}
453   public void mouseReleased(MouseEvent evt){ ap.paintAlignment(true);}
454   public void mouseEntered(MouseEvent evt){}
455   public void mouseExited(MouseEvent evt){}
456
457
458 }