2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
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.
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.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
23 import java.awt.event.*;
26 import javax.swing.event.*;
28 import net.miginfocom.swing.MigLayout;
30 import jalview.bin.Cache;
31 import jalview.datamodel.*;
32 import jalview.schemes.*;
33 import jalview.util.MessageManager;
35 import java.awt.Dimension;
37 public class AnnotationColourChooser extends JPanel
47 Hashtable oldgroupColours;
49 jalview.datamodel.AlignmentAnnotation currentAnnotation;
51 boolean adjusting = false;
53 * enabled if the user is dragging the slider - try to keep updates to a minimun
55 boolean sliderDragging = false;
57 public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
59 oldcs = av.getGlobalColourScheme();
60 if (av.getAlignment().getGroups() != null)
62 oldgroupColours = new Hashtable();
63 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
67 oldgroupColours.put(sg, sg.cs);
73 frame = new JInternalFrame();
74 frame.setContentPane(this);
75 frame.setLayer(JLayeredPane.PALETTE_LAYER);
76 Desktop.addInternalFrame(frame, "Colour by Annotation", 520, 215);
78 slider.addChangeListener(new ChangeListener()
80 public void stateChanged(ChangeEvent evt)
84 thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
85 valueChanged(!sliderDragging);
89 slider.addMouseListener(new MouseAdapter()
92 public void mousePressed(MouseEvent e)
95 super.mousePressed(e);
99 public void mouseDragged(MouseEvent e)
102 super.mouseDragged(e);
104 public void mouseReleased(MouseEvent evt)
108 sliderDragging=false;
111 ap.paintAlignment(true);
115 if (av.getAlignment().getAlignmentAnnotation() == null)
120 // Always get default shading from preferences.
124 if (oldcs instanceof AnnotationColourGradient)
126 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
127 currentColours.setSelected(acg.isPredefinedColours() || acg.getBaseColour()!=null);
128 if (!acg.isPredefinedColours() && acg.getBaseColour()==null)
130 minColour.setBackground(acg.getMinColour());
131 maxColour.setBackground(acg.getMaxColour());
133 seqAssociated.setSelected(acg.isSeqAssociated());
136 annotations = new JComboBox(
137 getAnnotationItems(seqAssociated.isSelected()));
139 threshold.addItem("No Threshold");
140 threshold.addItem("Above Threshold");
141 threshold.addItem("Below Threshold");
143 if (oldcs instanceof AnnotationColourGradient)
145 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
146 annotations.setSelectedItem(acg.getAnnotation());
147 switch (acg.getAboveThreshold())
149 case AnnotationColourGradient.NO_THRESHOLD:
150 threshold.setSelectedItem("No Threshold");
152 case AnnotationColourGradient.ABOVE_THRESHOLD:
153 threshold.setSelectedItem("Above Threshold");
155 case AnnotationColourGradient.BELOW_THRESHOLD:
156 threshold.setSelectedItem("Below Threshold");
160 "Implementation error: don't know about threshold setting for current AnnotationColourGradient.");
162 thresholdIsMin.setSelected(acg.thresholdIsMinMax);
163 thresholdValue.setText("" + acg.getAnnotationThreshold());
169 } catch (Exception ex)
181 private Vector<String> getAnnotationItems(boolean isSeqAssociated)
183 Vector<String> list = new Vector<String>();
185 int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
186 boolean enableSeqAss = false;
187 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
189 if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
200 String label = av.getAlignment().getAlignmentAnnotation()[i].label;
201 if (!list.contains(label))
203 anmap[list.size()] = i;
204 list.addElement(label);
209 if (!isSeqAssociated)
211 anmap[list.size()] = i;
212 list.addElement(label + "_" + (index++));
216 seqAssociated.setEnabled(enableSeqAss);
217 annmap = new int[list.size()];
218 System.arraycopy(anmap, 0, annmap, 0, annmap.length);
221 private void setDefaultMinMax()
223 minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
225 maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
229 public AnnotationColourChooser()
234 } catch (Exception ex)
236 ex.printStackTrace();
240 private void jbInit() throws Exception
242 minColour.setFont(JvSwingUtils.getLabelFont());
243 minColour.setBorder(BorderFactory.createEtchedBorder());
244 minColour.setPreferredSize(new Dimension(40, 20));
245 minColour.setToolTipText("Minimum Colour");
246 minColour.addMouseListener(new MouseAdapter()
248 public void mousePressed(MouseEvent e)
250 if (minColour.isEnabled())
252 minColour_actionPerformed();
256 maxColour.setFont(JvSwingUtils.getLabelFont());
257 maxColour.setBorder(BorderFactory.createEtchedBorder());
258 maxColour.setPreferredSize(new Dimension(40, 20));
259 maxColour.setToolTipText("Maximum Colour");
260 maxColour.addMouseListener(new MouseAdapter()
262 public void mousePressed(MouseEvent e)
264 if (maxColour.isEnabled())
266 maxColour_actionPerformed();
271 ok.setText(MessageManager.getString("action.ok"));
272 ok.addActionListener(new ActionListener()
274 public void actionPerformed(ActionEvent e)
276 ok_actionPerformed(e);
279 cancel.setOpaque(false);
280 cancel.setText(MessageManager.getString("action.cancel"));
281 cancel.addActionListener(new ActionListener()
283 public void actionPerformed(ActionEvent e)
285 cancel_actionPerformed(e);
288 defColours.setOpaque(false);
289 defColours.setText(MessageManager.getString("action.set_defaults"));
291 .setToolTipText("Reset min and max colours to defaults from user preferences.");
292 defColours.addActionListener(new ActionListener()
296 public void actionPerformed(ActionEvent arg0)
298 resetColours_actionPerformed(arg0);
302 annotations.addActionListener(new ActionListener()
304 public void actionPerformed(ActionEvent e)
306 annotations_actionPerformed(e);
309 threshold.addActionListener(new ActionListener()
311 public void actionPerformed(ActionEvent e)
313 threshold_actionPerformed(e);
316 thresholdValue.addActionListener(new ActionListener()
318 public void actionPerformed(ActionEvent e)
320 thresholdValue_actionPerformed(e);
323 slider.setPaintLabels(false);
324 slider.setPaintTicks(true);
325 slider.setBackground(Color.white);
326 slider.setEnabled(false);
327 slider.setOpaque(false);
328 slider.setPreferredSize(new Dimension(100, 32));
329 thresholdValue.setEnabled(false);
330 thresholdValue.setColumns(7);
331 currentColours.setFont(JvSwingUtils.getLabelFont());
332 currentColours.setOpaque(false);
333 currentColours.setText(MessageManager.getString("label.use_original_colours"));
334 currentColours.addActionListener(new ActionListener()
336 public void actionPerformed(ActionEvent e)
338 currentColours_actionPerformed(e);
341 thresholdIsMin.setBackground(Color.white);
342 thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
343 thresholdIsMin.setText(MessageManager.getString("label.threshold_minmax"));
344 thresholdIsMin.addActionListener(new ActionListener()
346 public void actionPerformed(ActionEvent actionEvent)
348 thresholdIsMin_actionPerformed(actionEvent);
351 seqAssociated.setBackground(Color.white);
352 seqAssociated.setFont(JvSwingUtils.getLabelFont());
353 seqAssociated.setText(MessageManager.getString("label.per_sequence_only"));
354 seqAssociated.addActionListener(new ActionListener()
358 public void actionPerformed(ActionEvent arg0)
360 seqAssociated_actionPerformed(arg0);
364 this.setLayout(borderLayout1);
365 jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
366 jPanel1.setBackground(Color.white);
367 jPanel2.setBackground(Color.white);
371 jPanel2.add(annotations, "grow, wrap");
372 jPanel2.add(seqAssociated);
373 jPanel2.add(currentColours);
374 JPanel colpanel = new JPanel(new FlowLayout());
375 colpanel.setBackground(Color.white);
376 colpanel.add(minColour);
377 colpanel.add(maxColour);
378 jPanel2.add(colpanel, "wrap");
379 jPanel2.add(threshold);
380 jPanel2.add(defColours, "skip 1, wrap");
381 jPanel2.add(thresholdIsMin);
382 jPanel2.add(slider, "grow");
383 jPanel2.add(thresholdValue, "grow");
384 this.add(jPanel1, java.awt.BorderLayout.SOUTH);
385 this.add(jPanel2, java.awt.BorderLayout.CENTER);
389 protected void seqAssociated_actionPerformed(ActionEvent arg0)
392 String cursel = (String) annotations.getSelectedItem();
393 boolean isvalid = false, isseqs = seqAssociated.isSelected();
394 this.annotations.removeAllItems();
395 for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
397 if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
402 this.annotations.addItem(anitem);
407 this.annotations.setSelectedItem(cursel);
411 if (annotations.getItemCount() > 0)
413 annotations.setSelectedIndex(0);
418 protected void resetColours_actionPerformed(ActionEvent arg0)
424 JComboBox annotations;
428 JPanel minColour = new JPanel();
430 JPanel maxColour = new JPanel();
432 JButton defColours = new JButton();
434 JButton ok = new JButton();
436 JButton cancel = new JButton();
438 JPanel jPanel1 = new JPanel();
440 JPanel jPanel2 = new JPanel();
442 BorderLayout borderLayout1 = new BorderLayout();
444 JComboBox threshold = new JComboBox();
446 JSlider slider = new JSlider();
448 JTextField thresholdValue = new JTextField(20);
450 JCheckBox currentColours = new JCheckBox();
452 JCheckBox thresholdIsMin = new JCheckBox();
454 JCheckBox seqAssociated = new JCheckBox();
456 public void minColour_actionPerformed()
458 Color col = JColorChooser.showDialog(this,
459 "Select Colour for Minimum Value", minColour.getBackground());
462 minColour.setBackground(col);
468 public void maxColour_actionPerformed()
470 Color col = JColorChooser.showDialog(this,
471 "Select Colour for Maximum Value", maxColour.getBackground());
474 maxColour.setBackground(col);
482 // Check if combobox is still adjusting
488 currentAnnotation = av.getAlignment().getAlignmentAnnotation()[annmap[annotations
489 .getSelectedIndex()]];
491 int aboveThreshold = -1;
492 if (threshold.getSelectedItem().equals("Above Threshold"))
494 aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
496 else if (threshold.getSelectedItem().equals("Below Threshold"))
498 aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
501 slider.setEnabled(true);
502 thresholdValue.setEnabled(true);
503 thresholdIsMin.setEnabled(true);
505 if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
507 slider.setEnabled(false);
508 thresholdValue.setEnabled(false);
509 thresholdValue.setText("");
510 thresholdIsMin.setEnabled(false);
512 else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
513 && currentAnnotation.threshold == null)
516 .setThreshold(new jalview.datamodel.GraphLine(
517 (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
518 "Threshold", Color.black));
521 if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
524 float range = currentAnnotation.graphMax * 1000
525 - currentAnnotation.graphMin * 1000;
527 slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
528 slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
529 slider.setValue((int) (currentAnnotation.threshold.value * 1000));
530 thresholdValue.setText(currentAnnotation.threshold.value + "");
531 slider.setMajorTickSpacing((int) (range / 10f));
532 slider.setEnabled(true);
533 thresholdValue.setEnabled(true);
537 AnnotationColourGradient acg = null;
538 if (currentColours.isSelected())
540 acg = new AnnotationColourGradient(currentAnnotation,
541 av.getGlobalColourScheme(), aboveThreshold);
545 acg = new AnnotationColourGradient(currentAnnotation,
546 minColour.getBackground(), maxColour.getBackground(),
549 acg.setSeqAssociated(seqAssociated.isSelected());
551 if (currentAnnotation.graphMin == 0f
552 && currentAnnotation.graphMax == 0f)
554 acg.setPredefinedColours(true);
557 acg.thresholdIsMinMax = thresholdIsMin.isSelected();
559 av.setGlobalColourScheme(acg);
561 if (av.getAlignment().getGroups() != null)
564 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
571 if (currentColours.isSelected())
573 sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
575 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
581 sg.cs = new AnnotationColourGradient(currentAnnotation,
582 minColour.getBackground(), maxColour.getBackground(),
584 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
590 ap.alignmentChanged();
591 // ensure all associated views (overviews, structures, etc) are notified of
593 ap.paintAlignment(true);
596 public void ok_actionPerformed(ActionEvent e)
601 frame.setClosed(true);
602 } catch (Exception ex)
607 public void cancel_actionPerformed(ActionEvent e)
610 // ensure all original colouring is propagated to listeners.
611 ap.paintAlignment(true);
614 frame.setClosed(true);
615 } catch (Exception ex)
622 av.setGlobalColourScheme(oldcs);
623 if (av.getAlignment().getGroups() != null)
626 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
628 sg.cs = (ColourSchemeI) oldgroupColours.get(sg);
633 public void thresholdCheck_actionPerformed(ActionEvent e)
638 public void annotations_actionPerformed(ActionEvent e)
643 public void threshold_actionPerformed(ActionEvent e)
648 public void thresholdValue_actionPerformed(ActionEvent e)
652 float f = Float.parseFloat(thresholdValue.getText());
653 slider.setValue((int) (f * 1000));
654 } catch (NumberFormatException ex)
659 public void valueChanged(boolean updateAllAnnotation)
661 if (currentColours.isSelected()
662 && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
666 currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
667 propagateSeqAssociatedThreshold(updateAllAnnotation);
668 ap.paintAlignment(false);
671 private void propagateSeqAssociatedThreshold(boolean allAnnotation)
673 if (currentAnnotation.sequenceRef == null
674 || currentAnnotation.threshold == null)
678 // TODO: JAL-1327 only update visible annotation thresholds if allAnnotation is false, since we only need to provide a quick visual indicator
680 float thr = currentAnnotation.threshold.value;
681 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
683 AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
684 if (aa.label.equals(currentAnnotation.label))
686 aa.threshold.value = thr;
691 public void currentColours_actionPerformed(ActionEvent e)
693 if (currentColours.isSelected())
698 maxColour.setEnabled(!currentColours.isSelected());
699 minColour.setEnabled(!currentColours.isSelected());
704 public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)