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.
123 if (oldcs instanceof AnnotationColourGradient)
125 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
126 currentColours.setSelected(acg.isPredefinedColours());
127 if (!acg.isPredefinedColours())
129 minColour.setBackground(acg.getMinColour());
130 maxColour.setBackground(acg.getMaxColour());
132 seqAssociated.setSelected(acg.isSeqAssociated());
135 annotations = new JComboBox(
136 getAnnotationItems(seqAssociated.isSelected()));
138 threshold.addItem("No Threshold");
139 threshold.addItem("Above Threshold");
140 threshold.addItem("Below Threshold");
142 if (oldcs instanceof AnnotationColourGradient)
144 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
145 annotations.setSelectedItem(acg.getAnnotation());
146 switch (acg.getAboveThreshold())
148 case AnnotationColourGradient.NO_THRESHOLD:
149 threshold.setSelectedItem("No Threshold");
151 case AnnotationColourGradient.ABOVE_THRESHOLD:
152 threshold.setSelectedItem("Above Threshold");
154 case AnnotationColourGradient.BELOW_THRESHOLD:
155 threshold.setSelectedItem("Below Threshold");
159 "Implementation error: don't know about threshold setting for current AnnotationColourGradient.");
161 thresholdIsMin.setSelected(acg.thresholdIsMinMax);
162 thresholdValue.setText("" + acg.getAnnotationThreshold());
168 } catch (Exception ex)
180 private Vector<String> getAnnotationItems(boolean isSeqAssociated)
182 Vector<String> list = new Vector<String>();
184 int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
185 boolean enableSeqAss = false;
186 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
188 if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
199 String label = av.getAlignment().getAlignmentAnnotation()[i].label;
200 if (!list.contains(label))
202 anmap[list.size()] = i;
203 list.addElement(label);
208 if (!isSeqAssociated)
210 anmap[list.size()] = i;
211 list.addElement(label + "_" + (index++));
215 seqAssociated.setEnabled(enableSeqAss);
216 annmap = new int[list.size()];
217 System.arraycopy(anmap, 0, annmap, 0, annmap.length);
220 private void setDefaultMinMax()
222 minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
224 maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
228 public AnnotationColourChooser()
233 } catch (Exception ex)
235 ex.printStackTrace();
239 private void jbInit() throws Exception
241 minColour.setFont(JvSwingUtils.getLabelFont());
242 minColour.setBorder(BorderFactory.createEtchedBorder());
243 minColour.setPreferredSize(new Dimension(40, 20));
244 minColour.setToolTipText("Minimum Colour");
245 minColour.addMouseListener(new MouseAdapter()
247 public void mousePressed(MouseEvent e)
249 if (minColour.isEnabled())
251 minColour_actionPerformed();
255 maxColour.setFont(JvSwingUtils.getLabelFont());
256 maxColour.setBorder(BorderFactory.createEtchedBorder());
257 maxColour.setPreferredSize(new Dimension(40, 20));
258 maxColour.setToolTipText("Maximum Colour");
259 maxColour.addMouseListener(new MouseAdapter()
261 public void mousePressed(MouseEvent e)
263 if (maxColour.isEnabled())
265 maxColour_actionPerformed();
270 ok.setText(MessageManager.getString("action.ok"));
271 ok.addActionListener(new ActionListener()
273 public void actionPerformed(ActionEvent e)
275 ok_actionPerformed(e);
278 cancel.setOpaque(false);
279 cancel.setText(MessageManager.getString("action.cancel"));
280 cancel.addActionListener(new ActionListener()
282 public void actionPerformed(ActionEvent e)
284 cancel_actionPerformed(e);
287 defColours.setOpaque(false);
288 defColours.setText(MessageManager.getString("action.set_defaults"));
290 .setToolTipText("Reset min and max colours to defaults from user preferences.");
291 defColours.addActionListener(new ActionListener()
295 public void actionPerformed(ActionEvent arg0)
297 resetColours_actionPerformed(arg0);
301 annotations.addActionListener(new ActionListener()
303 public void actionPerformed(ActionEvent e)
305 annotations_actionPerformed(e);
308 threshold.addActionListener(new ActionListener()
310 public void actionPerformed(ActionEvent e)
312 threshold_actionPerformed(e);
315 thresholdValue.addActionListener(new ActionListener()
317 public void actionPerformed(ActionEvent e)
319 thresholdValue_actionPerformed(e);
322 slider.setPaintLabels(false);
323 slider.setPaintTicks(true);
324 slider.setBackground(Color.white);
325 slider.setEnabled(false);
326 slider.setOpaque(false);
327 slider.setPreferredSize(new Dimension(100, 32));
328 thresholdValue.setEnabled(false);
329 thresholdValue.setColumns(7);
330 currentColours.setFont(JvSwingUtils.getLabelFont());
331 currentColours.setOpaque(false);
332 currentColours.setText(MessageManager.getString("label.use_original_colours"));
333 currentColours.addActionListener(new ActionListener()
335 public void actionPerformed(ActionEvent e)
337 currentColours_actionPerformed(e);
340 thresholdIsMin.setBackground(Color.white);
341 thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
342 thresholdIsMin.setText(MessageManager.getString("label.threshold_minmax"));
343 thresholdIsMin.addActionListener(new ActionListener()
345 public void actionPerformed(ActionEvent actionEvent)
347 thresholdIsMin_actionPerformed(actionEvent);
350 seqAssociated.setBackground(Color.white);
351 seqAssociated.setFont(JvSwingUtils.getLabelFont());
352 seqAssociated.setText(MessageManager.getString("label.per_sequence_only"));
353 seqAssociated.addActionListener(new ActionListener()
357 public void actionPerformed(ActionEvent arg0)
359 seqAssociated_actionPerformed(arg0);
363 this.setLayout(borderLayout1);
364 jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
365 jPanel1.setBackground(Color.white);
366 jPanel2.setBackground(Color.white);
370 jPanel2.add(annotations, "grow, wrap");
371 jPanel2.add(seqAssociated);
372 jPanel2.add(currentColours);
373 JPanel colpanel = new JPanel(new FlowLayout());
374 colpanel.setBackground(Color.white);
375 colpanel.add(minColour);
376 colpanel.add(maxColour);
377 jPanel2.add(colpanel, "wrap");
378 jPanel2.add(threshold);
379 jPanel2.add(defColours, "skip 1, wrap");
380 jPanel2.add(thresholdIsMin);
381 jPanel2.add(slider, "grow");
382 jPanel2.add(thresholdValue, "grow");
383 this.add(jPanel1, java.awt.BorderLayout.SOUTH);
384 this.add(jPanel2, java.awt.BorderLayout.CENTER);
388 protected void seqAssociated_actionPerformed(ActionEvent arg0)
391 String cursel = (String) annotations.getSelectedItem();
392 boolean isvalid = false, isseqs = seqAssociated.isSelected();
393 this.annotations.removeAllItems();
394 for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
396 if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
401 this.annotations.addItem(anitem);
406 this.annotations.setSelectedItem(cursel);
410 if (annotations.getItemCount() > 0)
412 annotations.setSelectedIndex(0);
417 protected void resetColours_actionPerformed(ActionEvent arg0)
423 JComboBox annotations;
427 JPanel minColour = new JPanel();
429 JPanel maxColour = new JPanel();
431 JButton defColours = new JButton();
433 JButton ok = new JButton();
435 JButton cancel = new JButton();
437 JPanel jPanel1 = new JPanel();
439 JPanel jPanel2 = new JPanel();
441 BorderLayout borderLayout1 = new BorderLayout();
443 JComboBox threshold = new JComboBox();
445 JSlider slider = new JSlider();
447 JTextField thresholdValue = new JTextField(20);
449 JCheckBox currentColours = new JCheckBox();
451 JCheckBox thresholdIsMin = new JCheckBox();
453 JCheckBox seqAssociated = new JCheckBox();
455 public void minColour_actionPerformed()
457 Color col = JColorChooser.showDialog(this,
458 "Select Colour for Minimum Value", minColour.getBackground());
461 minColour.setBackground(col);
467 public void maxColour_actionPerformed()
469 Color col = JColorChooser.showDialog(this,
470 "Select Colour for Maximum Value", maxColour.getBackground());
473 maxColour.setBackground(col);
481 // Check if combobox is still adjusting
487 currentAnnotation = av.getAlignment().getAlignmentAnnotation()[annmap[annotations
488 .getSelectedIndex()]];
490 int aboveThreshold = -1;
491 if (threshold.getSelectedItem().equals("Above Threshold"))
493 aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
495 else if (threshold.getSelectedItem().equals("Below Threshold"))
497 aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
500 slider.setEnabled(true);
501 thresholdValue.setEnabled(true);
502 thresholdIsMin.setEnabled(true);
504 if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
506 slider.setEnabled(false);
507 thresholdValue.setEnabled(false);
508 thresholdValue.setText("");
509 thresholdIsMin.setEnabled(false);
511 else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
512 && currentAnnotation.threshold == null)
515 .setThreshold(new jalview.datamodel.GraphLine(
516 (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
517 "Threshold", Color.black));
520 if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
523 float range = currentAnnotation.graphMax * 1000
524 - currentAnnotation.graphMin * 1000;
526 slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
527 slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
528 slider.setValue((int) (currentAnnotation.threshold.value * 1000));
529 thresholdValue.setText(currentAnnotation.threshold.value + "");
530 slider.setMajorTickSpacing((int) (range / 10f));
531 slider.setEnabled(true);
532 thresholdValue.setEnabled(true);
536 AnnotationColourGradient acg = null;
537 if (currentColours.isSelected())
539 acg = new AnnotationColourGradient(currentAnnotation,
540 av.getGlobalColourScheme(), aboveThreshold);
544 acg = new AnnotationColourGradient(currentAnnotation,
545 minColour.getBackground(), maxColour.getBackground(),
548 acg.setSeqAssociated(seqAssociated.isSelected());
550 if (currentAnnotation.graphMin == 0f
551 && currentAnnotation.graphMax == 0f)
553 acg.setPredefinedColours(true);
556 acg.thresholdIsMinMax = thresholdIsMin.isSelected();
558 av.setGlobalColourScheme(acg);
560 if (av.getAlignment().getGroups() != null)
563 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
570 if (currentColours.isSelected())
572 sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
574 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
580 sg.cs = new AnnotationColourGradient(currentAnnotation,
581 minColour.getBackground(), maxColour.getBackground(),
583 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
589 ap.alignmentChanged();
590 // ensure all associated views (overviews, structures, etc) are notified of
592 ap.paintAlignment(true);
595 public void ok_actionPerformed(ActionEvent e)
600 frame.setClosed(true);
601 } catch (Exception ex)
606 public void cancel_actionPerformed(ActionEvent e)
609 // ensure all original colouring is propagated to listeners.
610 ap.paintAlignment(true);
613 frame.setClosed(true);
614 } catch (Exception ex)
621 av.setGlobalColourScheme(oldcs);
622 if (av.getAlignment().getGroups() != null)
625 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
627 sg.cs = (ColourSchemeI) oldgroupColours.get(sg);
632 public void thresholdCheck_actionPerformed(ActionEvent e)
637 public void annotations_actionPerformed(ActionEvent e)
642 public void threshold_actionPerformed(ActionEvent e)
647 public void thresholdValue_actionPerformed(ActionEvent e)
651 float f = Float.parseFloat(thresholdValue.getText());
652 slider.setValue((int) (f * 1000));
653 } catch (NumberFormatException ex)
658 public void valueChanged(boolean updateAllAnnotation)
660 if (currentColours.isSelected()
661 && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
665 currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
666 propagateSeqAssociatedThreshold(updateAllAnnotation);
667 ap.paintAlignment(false);
670 private void propagateSeqAssociatedThreshold(boolean allAnnotation)
672 if (currentAnnotation.sequenceRef == null
673 || currentAnnotation.threshold == null)
677 // TODO: JAL-1327 only update visible annotation thresholds if allAnnotation is false, since we only need to provide a quick visual indicator
679 float thr = currentAnnotation.threshold.value;
680 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
682 AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
683 if (aa.label.equals(currentAnnotation.label))
685 aa.threshold.value = thr;
690 public void currentColours_actionPerformed(ActionEvent e)
692 if (currentColours.isSelected())
697 maxColour.setEnabled(!currentColours.isSelected());
698 minColour.setEnabled(!currentColours.isSelected());
703 public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)