2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 The Jalview Authors
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
10 * of the License, or (at your option) any later version.
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.
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.
23 import jalview.bin.Cache;
24 import jalview.datamodel.AlignmentAnnotation;
25 import jalview.datamodel.SequenceGroup;
26 import jalview.schemes.AnnotationColourGradient;
27 import jalview.schemes.ColourSchemeI;
28 import jalview.util.MessageManager;
30 import java.awt.BorderLayout;
31 import java.awt.Color;
32 import java.awt.Dimension;
33 import java.awt.FlowLayout;
34 import java.awt.event.ActionEvent;
35 import java.awt.event.ActionListener;
36 import java.awt.event.MouseAdapter;
37 import java.awt.event.MouseEvent;
38 import java.util.Hashtable;
39 import java.util.Vector;
41 import javax.swing.BorderFactory;
42 import javax.swing.JButton;
43 import javax.swing.JCheckBox;
44 import javax.swing.JColorChooser;
45 import javax.swing.JComboBox;
46 import javax.swing.JInternalFrame;
47 import javax.swing.JLayeredPane;
48 import javax.swing.JPanel;
49 import javax.swing.JSlider;
50 import javax.swing.JTextField;
51 import javax.swing.event.ChangeEvent;
52 import javax.swing.event.ChangeListener;
54 import net.miginfocom.swing.MigLayout;
56 public class AnnotationColourChooser extends JPanel
66 Hashtable oldgroupColours;
68 jalview.datamodel.AlignmentAnnotation currentAnnotation;
70 boolean adjusting = false;
73 * enabled if the user is dragging the slider - try to keep updates to a
76 boolean sliderDragging = false;
78 public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
80 oldcs = av.getGlobalColourScheme();
81 if (av.getAlignment().getGroups() != null)
83 oldgroupColours = new Hashtable();
84 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
88 oldgroupColours.put(sg, sg.cs);
94 frame = new JInternalFrame();
95 frame.setContentPane(this);
96 frame.setLayer(JLayeredPane.PALETTE_LAYER);
97 Desktop.addInternalFrame(frame,
98 MessageManager.getString("label.colour_by_annotation"), 520,
101 slider.addChangeListener(new ChangeListener()
104 public void stateChanged(ChangeEvent evt)
108 thresholdValue.setText((slider.getValue() / 1000f) + "");
109 valueChanged(!sliderDragging);
113 slider.addMouseListener(new MouseAdapter()
116 public void mousePressed(MouseEvent e)
118 sliderDragging = true;
119 super.mousePressed(e);
123 public void mouseDragged(MouseEvent e)
125 sliderDragging = true;
126 super.mouseDragged(e);
130 public void mouseReleased(MouseEvent evt)
134 sliderDragging = false;
137 ap.paintAlignment(true);
141 if (av.getAlignment().getAlignmentAnnotation() == null)
146 // Always get default shading from preferences.
150 if (oldcs instanceof AnnotationColourGradient)
152 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
153 currentColours.setSelected(acg.isPredefinedColours()
154 || acg.getBaseColour() != null);
155 if (!acg.isPredefinedColours() && acg.getBaseColour() == null)
157 minColour.setBackground(acg.getMinColour());
158 maxColour.setBackground(acg.getMaxColour());
160 seqAssociated.setSelected(acg.isSeqAssociated());
163 annotations = new JComboBox(
164 getAnnotationItems(seqAssociated.isSelected()));
166 threshold.addItem(MessageManager
167 .getString("label.threshold_feature_no_thereshold"));
168 threshold.addItem(MessageManager
169 .getString("label.threshold_feature_above_thereshold"));
170 threshold.addItem(MessageManager
171 .getString("label.threshold_feature_below_thereshold"));
173 if (oldcs instanceof AnnotationColourGradient)
175 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
176 annotations.setSelectedItem(acg.getAnnotation());
177 switch (acg.getAboveThreshold())
179 case AnnotationColourGradient.NO_THRESHOLD:
180 threshold.setSelectedIndex(0);
182 case AnnotationColourGradient.ABOVE_THRESHOLD:
183 threshold.setSelectedIndex(1);
185 case AnnotationColourGradient.BELOW_THRESHOLD:
186 threshold.setSelectedIndex(2);
189 throw new Error(MessageManager.getString("error.implementation_error_dont_know_about_thereshold_setting"));
191 thresholdIsMin.setSelected(acg.thresholdIsMinMax);
192 thresholdValue.setText("" + acg.getAnnotationThreshold());
198 } catch (Exception ex)
210 private Vector<String> getAnnotationItems(boolean isSeqAssociated)
212 Vector<String> list = new Vector<String>();
214 int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
215 boolean enableSeqAss = false;
216 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
218 if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
229 String label = av.getAlignment().getAlignmentAnnotation()[i].label;
230 if (!list.contains(label))
232 anmap[list.size()] = i;
238 if (!isSeqAssociated)
240 anmap[list.size()] = i;
241 list.add(label + "_" + (index++));
245 seqAssociated.setEnabled(enableSeqAss);
246 this.annmap = new int[list.size()];
247 System.arraycopy(anmap, 0, this.annmap, 0, this.annmap.length);
251 private void setDefaultMinMax()
253 minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
255 maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
259 public AnnotationColourChooser()
264 } catch (Exception ex)
266 ex.printStackTrace();
270 private void jbInit() throws Exception
272 minColour.setFont(JvSwingUtils.getLabelFont());
273 minColour.setBorder(BorderFactory.createEtchedBorder());
274 minColour.setPreferredSize(new Dimension(40, 20));
275 minColour.setToolTipText(MessageManager.getString("label.min_colour"));
276 minColour.addMouseListener(new MouseAdapter()
279 public void mousePressed(MouseEvent e)
281 if (minColour.isEnabled())
283 minColour_actionPerformed();
287 maxColour.setFont(JvSwingUtils.getLabelFont());
288 maxColour.setBorder(BorderFactory.createEtchedBorder());
289 maxColour.setPreferredSize(new Dimension(40, 20));
290 maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
291 maxColour.addMouseListener(new MouseAdapter()
294 public void mousePressed(MouseEvent e)
296 if (maxColour.isEnabled())
298 maxColour_actionPerformed();
303 ok.setText(MessageManager.getString("action.ok"));
304 ok.addActionListener(new ActionListener()
307 public void actionPerformed(ActionEvent e)
309 ok_actionPerformed(e);
312 cancel.setOpaque(false);
313 cancel.setText(MessageManager.getString("action.cancel"));
314 cancel.addActionListener(new ActionListener()
317 public void actionPerformed(ActionEvent e)
319 cancel_actionPerformed(e);
322 defColours.setOpaque(false);
323 defColours.setText(MessageManager.getString("action.set_defaults"));
324 defColours.setToolTipText(MessageManager
325 .getString("label.reset_min_max_colours_to_defaults"));
326 defColours.addActionListener(new ActionListener()
330 public void actionPerformed(ActionEvent arg0)
332 resetColours_actionPerformed(arg0);
336 annotations.addActionListener(new ActionListener()
339 public void actionPerformed(ActionEvent e)
341 annotations_actionPerformed(e);
344 threshold.addActionListener(new ActionListener()
347 public void actionPerformed(ActionEvent e)
349 threshold_actionPerformed(e);
352 thresholdValue.addActionListener(new ActionListener()
355 public void actionPerformed(ActionEvent e)
357 thresholdValue_actionPerformed(e);
360 slider.setPaintLabels(false);
361 slider.setPaintTicks(true);
362 slider.setBackground(Color.white);
363 slider.setEnabled(false);
364 slider.setOpaque(false);
365 slider.setPreferredSize(new Dimension(100, 32));
366 thresholdValue.setEnabled(false);
367 thresholdValue.setColumns(7);
368 currentColours.setFont(JvSwingUtils.getLabelFont());
369 currentColours.setOpaque(false);
370 currentColours.setText(MessageManager
371 .getString("label.use_original_colours"));
372 currentColours.addActionListener(new ActionListener()
375 public void actionPerformed(ActionEvent e)
377 currentColours_actionPerformed(e);
380 thresholdIsMin.setBackground(Color.white);
381 thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
382 thresholdIsMin.setText(MessageManager
383 .getString("label.threshold_minmax"));
384 thresholdIsMin.addActionListener(new ActionListener()
387 public void actionPerformed(ActionEvent actionEvent)
389 thresholdIsMin_actionPerformed(actionEvent);
392 seqAssociated.setBackground(Color.white);
393 seqAssociated.setFont(JvSwingUtils.getLabelFont());
394 seqAssociated.setText(MessageManager
395 .getString("label.per_sequence_only"));
396 seqAssociated.addActionListener(new ActionListener()
400 public void actionPerformed(ActionEvent arg0)
402 seqAssociated_actionPerformed(arg0);
406 this.setLayout(borderLayout1);
407 jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
408 jPanel1.setBackground(Color.white);
409 jPanel2.setBackground(Color.white);
413 jPanel2.add(annotations, "grow, wrap");
414 jPanel2.add(seqAssociated);
415 jPanel2.add(currentColours);
416 JPanel colpanel = new JPanel(new FlowLayout());
417 colpanel.setBackground(Color.white);
418 colpanel.add(minColour);
419 colpanel.add(maxColour);
420 jPanel2.add(colpanel, "wrap");
421 jPanel2.add(threshold);
422 jPanel2.add(defColours, "skip 1, wrap");
423 jPanel2.add(thresholdIsMin);
424 jPanel2.add(slider, "grow");
425 jPanel2.add(thresholdValue, "grow");
426 this.add(jPanel1, java.awt.BorderLayout.SOUTH);
427 this.add(jPanel2, java.awt.BorderLayout.CENTER);
431 protected void seqAssociated_actionPerformed(ActionEvent arg0)
434 String cursel = (String) annotations.getSelectedItem();
435 boolean isvalid = false, isseqs = seqAssociated.isSelected();
436 this.annotations.removeAllItems();
437 for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
439 if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
444 this.annotations.addItem(anitem);
449 this.annotations.setSelectedItem(cursel);
453 if (annotations.getItemCount() > 0)
455 annotations.setSelectedIndex(0);
460 protected void resetColours_actionPerformed(ActionEvent arg0)
466 JComboBox annotations;
470 JPanel minColour = new JPanel();
472 JPanel maxColour = new JPanel();
474 JButton defColours = new JButton();
476 JButton ok = new JButton();
478 JButton cancel = new JButton();
480 JPanel jPanel1 = new JPanel();
482 JPanel jPanel2 = new JPanel();
484 BorderLayout borderLayout1 = new BorderLayout();
486 JComboBox threshold = new JComboBox();
488 JSlider slider = new JSlider();
490 JTextField thresholdValue = new JTextField(20);
492 JCheckBox currentColours = new JCheckBox();
494 JCheckBox thresholdIsMin = new JCheckBox();
496 JCheckBox seqAssociated = new JCheckBox();
498 public void minColour_actionPerformed()
500 Color col = JColorChooser.showDialog(this,
501 MessageManager.getString("label.select_colour_minimum_value"), minColour.getBackground());
504 minColour.setBackground(col);
510 public void maxColour_actionPerformed()
512 Color col = JColorChooser.showDialog(this,
513 MessageManager.getString("label.select_colour_maximum_value"), maxColour.getBackground());
516 maxColour.setBackground(col);
524 // Check if combobox is still adjusting
530 currentAnnotation = av.getAlignment().getAlignmentAnnotation()[annmap[annotations
531 .getSelectedIndex()]];
533 int aboveThreshold = -1;
534 if (threshold.getSelectedIndex() == 1)
536 aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
538 else if (threshold.getSelectedIndex() == 2)
540 aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
543 slider.setEnabled(true);
544 thresholdValue.setEnabled(true);
545 thresholdIsMin.setEnabled(true);
547 if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
549 slider.setEnabled(false);
550 thresholdValue.setEnabled(false);
551 thresholdValue.setText("");
552 thresholdIsMin.setEnabled(false);
554 else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
555 && currentAnnotation.threshold == null)
558 .setThreshold(new jalview.datamodel.GraphLine(
559 (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
560 "Threshold", Color.black));
563 if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
566 float range = currentAnnotation.graphMax * 1000
567 - currentAnnotation.graphMin * 1000;
569 slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
570 slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
571 slider.setValue((int) (currentAnnotation.threshold.value * 1000));
572 thresholdValue.setText(currentAnnotation.threshold.value + "");
573 slider.setMajorTickSpacing((int) (range / 10f));
574 slider.setEnabled(true);
575 thresholdValue.setEnabled(true);
579 AnnotationColourGradient acg = null;
580 if (currentColours.isSelected())
582 acg = new AnnotationColourGradient(currentAnnotation,
583 av.getGlobalColourScheme(), aboveThreshold);
587 acg = new AnnotationColourGradient(currentAnnotation,
588 minColour.getBackground(), maxColour.getBackground(),
591 acg.setSeqAssociated(seqAssociated.isSelected());
593 if (currentAnnotation.graphMin == 0f
594 && currentAnnotation.graphMax == 0f)
596 acg.setPredefinedColours(true);
599 acg.thresholdIsMinMax = thresholdIsMin.isSelected();
601 av.setGlobalColourScheme(acg);
603 if (av.getAlignment().getGroups() != null)
606 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
613 if (currentColours.isSelected())
615 sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
617 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
623 sg.cs = new AnnotationColourGradient(currentAnnotation,
624 minColour.getBackground(), maxColour.getBackground(),
626 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
632 ap.alignmentChanged();
633 // ensure all associated views (overviews, structures, etc) are notified of
635 ap.paintAlignment(true);
638 public void ok_actionPerformed(ActionEvent e)
643 frame.setClosed(true);
644 } catch (Exception ex)
649 public void cancel_actionPerformed(ActionEvent e)
652 // ensure all original colouring is propagated to listeners.
653 ap.paintAlignment(true);
656 frame.setClosed(true);
657 } catch (Exception ex)
664 av.setGlobalColourScheme(oldcs);
665 if (av.getAlignment().getGroups() != null)
668 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
670 sg.cs = (ColourSchemeI) oldgroupColours.get(sg);
675 public void thresholdCheck_actionPerformed(ActionEvent e)
680 public void annotations_actionPerformed(ActionEvent e)
685 public void threshold_actionPerformed(ActionEvent e)
690 public void thresholdValue_actionPerformed(ActionEvent e)
694 float f = Float.parseFloat(thresholdValue.getText());
695 slider.setValue((int) (f * 1000));
696 } catch (NumberFormatException ex)
701 public void valueChanged(boolean updateAllAnnotation)
703 if (currentColours.isSelected()
704 && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
708 currentAnnotation.threshold.value = slider.getValue() / 1000f;
709 propagateSeqAssociatedThreshold(updateAllAnnotation);
710 ap.paintAlignment(false);
713 private void propagateSeqAssociatedThreshold(boolean allAnnotation)
715 if (currentAnnotation.sequenceRef == null
716 || currentAnnotation.threshold == null)
720 // TODO: JAL-1327 only update visible annotation thresholds if allAnnotation
721 // is false, since we only need to provide a quick visual indicator
723 float thr = currentAnnotation.threshold.value;
724 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
726 AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
727 if (aa.label.equals(currentAnnotation.label))
729 aa.threshold.value = thr;
734 public void currentColours_actionPerformed(ActionEvent e)
736 if (currentColours.isSelected())
741 maxColour.setEnabled(!currentColours.isSelected());
742 minColour.setEnabled(!currentColours.isSelected());
747 public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)