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 java.awt.Dimension;
35 public class AnnotationColourChooser extends JPanel
45 Hashtable oldgroupColours;
47 jalview.datamodel.AlignmentAnnotation currentAnnotation;
49 boolean adjusting = false;
51 * enabled if the user is dragging the slider - try to keep updates to a minimun
53 boolean sliderDragging = false;
55 public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
57 oldcs = av.getGlobalColourScheme();
58 if (av.getAlignment().getGroups() != null)
60 oldgroupColours = new Hashtable();
61 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
65 oldgroupColours.put(sg, sg.cs);
71 frame = new JInternalFrame();
72 frame.setContentPane(this);
73 frame.setLayer(JLayeredPane.PALETTE_LAYER);
74 Desktop.addInternalFrame(frame, "Colour by Annotation", 520, 215);
76 slider.addChangeListener(new ChangeListener()
78 public void stateChanged(ChangeEvent evt)
82 thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
83 valueChanged(!sliderDragging);
87 slider.addMouseListener(new MouseAdapter()
90 public void mousePressed(MouseEvent e)
93 super.mousePressed(e);
97 public void mouseDragged(MouseEvent e)
100 super.mouseDragged(e);
102 public void mouseReleased(MouseEvent evt)
106 sliderDragging=false;
109 ap.paintAlignment(true);
113 if (av.getAlignment().getAlignmentAnnotation() == null)
118 // Always get default shading from preferences.
121 if (oldcs instanceof AnnotationColourGradient)
123 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
124 currentColours.setSelected(acg.predefinedColours);
125 if (!acg.predefinedColours)
127 minColour.setBackground(acg.getMinColour());
128 maxColour.setBackground(acg.getMaxColour());
130 seqAssociated.setSelected(acg.isSeqAssociated());
133 annotations = new JComboBox(
134 getAnnotationItems(seqAssociated.isSelected()));
136 threshold.addItem("No Threshold");
137 threshold.addItem("Above Threshold");
138 threshold.addItem("Below Threshold");
140 if (oldcs instanceof AnnotationColourGradient)
142 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
143 annotations.setSelectedItem(acg.getAnnotation());
144 switch (acg.getAboveThreshold())
146 case AnnotationColourGradient.NO_THRESHOLD:
147 threshold.setSelectedItem("No Threshold");
149 case AnnotationColourGradient.ABOVE_THRESHOLD:
150 threshold.setSelectedItem("Above Threshold");
152 case AnnotationColourGradient.BELOW_THRESHOLD:
153 threshold.setSelectedItem("Below Threshold");
157 "Implementation error: don't know about threshold setting for current AnnotationColourGradient.");
159 thresholdIsMin.setSelected(acg.thresholdIsMinMax);
160 thresholdValue.setText("" + acg.getAnnotationThreshold());
166 } catch (Exception ex)
178 private Vector<String> getAnnotationItems(boolean isSeqAssociated)
180 Vector<String> list = new Vector<String>();
182 int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
183 boolean enableSeqAss = false;
184 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
186 if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
197 String label = av.getAlignment().getAlignmentAnnotation()[i].label;
198 if (!list.contains(label))
200 anmap[list.size()] = i;
201 list.addElement(label);
206 if (!isSeqAssociated)
208 anmap[list.size()] = i;
209 list.addElement(label + "_" + (index++));
213 seqAssociated.setEnabled(enableSeqAss);
214 annmap = new int[list.size()];
215 System.arraycopy(anmap, 0, annmap, 0, annmap.length);
218 private void setDefaultMinMax()
220 minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
222 maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
226 public AnnotationColourChooser()
231 } catch (Exception ex)
233 ex.printStackTrace();
237 private void jbInit() throws Exception
239 minColour.setFont(JvSwingUtils.getLabelFont());
240 minColour.setBorder(BorderFactory.createEtchedBorder());
241 minColour.setPreferredSize(new Dimension(40, 20));
242 minColour.setToolTipText("Minimum Colour");
243 minColour.addMouseListener(new MouseAdapter()
245 public void mousePressed(MouseEvent e)
247 if (minColour.isEnabled())
249 minColour_actionPerformed();
253 maxColour.setFont(JvSwingUtils.getLabelFont());
254 maxColour.setBorder(BorderFactory.createEtchedBorder());
255 maxColour.setPreferredSize(new Dimension(40, 20));
256 maxColour.setToolTipText("Maximum Colour");
257 maxColour.addMouseListener(new MouseAdapter()
259 public void mousePressed(MouseEvent e)
261 if (maxColour.isEnabled())
263 maxColour_actionPerformed();
269 ok.addActionListener(new ActionListener()
271 public void actionPerformed(ActionEvent e)
273 ok_actionPerformed(e);
276 cancel.setOpaque(false);
277 cancel.setText("Cancel");
278 cancel.addActionListener(new ActionListener()
280 public void actionPerformed(ActionEvent e)
282 cancel_actionPerformed(e);
285 defColours.setOpaque(false);
286 defColours.setText("Defaults");
288 .setToolTipText("Reset min and max colours to defaults from user preferences.");
289 defColours.addActionListener(new ActionListener()
293 public void actionPerformed(ActionEvent arg0)
295 resetColours_actionPerformed(arg0);
299 annotations.addActionListener(new ActionListener()
301 public void actionPerformed(ActionEvent e)
303 annotations_actionPerformed(e);
306 threshold.addActionListener(new ActionListener()
308 public void actionPerformed(ActionEvent e)
310 threshold_actionPerformed(e);
313 thresholdValue.addActionListener(new ActionListener()
315 public void actionPerformed(ActionEvent e)
317 thresholdValue_actionPerformed(e);
320 slider.setPaintLabels(false);
321 slider.setPaintTicks(true);
322 slider.setBackground(Color.white);
323 slider.setEnabled(false);
324 slider.setOpaque(false);
325 slider.setPreferredSize(new Dimension(100, 32));
326 thresholdValue.setEnabled(false);
327 thresholdValue.setColumns(7);
328 currentColours.setFont(JvSwingUtils.getLabelFont());
329 currentColours.setOpaque(false);
330 currentColours.setText("Use Original Colours");
331 currentColours.addActionListener(new ActionListener()
333 public void actionPerformed(ActionEvent e)
335 currentColours_actionPerformed(e);
338 thresholdIsMin.setBackground(Color.white);
339 thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
340 thresholdIsMin.setText("Threshold is Min/Max");
341 thresholdIsMin.addActionListener(new ActionListener()
343 public void actionPerformed(ActionEvent actionEvent)
345 thresholdIsMin_actionPerformed(actionEvent);
348 seqAssociated.setBackground(Color.white);
349 seqAssociated.setFont(JvSwingUtils.getLabelFont());
350 seqAssociated.setText("Per-sequence only");
351 seqAssociated.addActionListener(new ActionListener()
355 public void actionPerformed(ActionEvent arg0)
357 seqAssociated_actionPerformed(arg0);
361 this.setLayout(borderLayout1);
362 jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
363 jPanel1.setBackground(Color.white);
364 jPanel2.setBackground(Color.white);
368 jPanel2.add(annotations, "grow, wrap");
369 jPanel2.add(seqAssociated);
370 jPanel2.add(currentColours);
371 JPanel colpanel = new JPanel(new FlowLayout());
372 colpanel.setBackground(Color.white);
373 colpanel.add(minColour);
374 colpanel.add(maxColour);
375 jPanel2.add(colpanel, "wrap");
376 jPanel2.add(threshold);
377 jPanel2.add(defColours, "skip 1, wrap");
378 jPanel2.add(thresholdIsMin);
379 jPanel2.add(slider, "grow");
380 jPanel2.add(thresholdValue, "grow");
381 this.add(jPanel1, java.awt.BorderLayout.SOUTH);
382 this.add(jPanel2, java.awt.BorderLayout.CENTER);
386 protected void seqAssociated_actionPerformed(ActionEvent arg0)
389 String cursel = (String) annotations.getSelectedItem();
390 boolean isvalid = false, isseqs = seqAssociated.isSelected();
391 this.annotations.removeAllItems();
392 for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
394 if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
399 this.annotations.addItem(anitem);
404 this.annotations.setSelectedItem(cursel);
408 if (annotations.getItemCount() > 0)
410 annotations.setSelectedIndex(0);
415 protected void resetColours_actionPerformed(ActionEvent arg0)
421 JComboBox annotations;
425 JPanel minColour = new JPanel();
427 JPanel maxColour = new JPanel();
429 JButton defColours = new JButton();
431 JButton ok = new JButton();
433 JButton cancel = new JButton();
435 JPanel jPanel1 = new JPanel();
437 JPanel jPanel2 = new JPanel();
439 BorderLayout borderLayout1 = new BorderLayout();
441 JComboBox threshold = new JComboBox();
443 JSlider slider = new JSlider();
445 JTextField thresholdValue = new JTextField(20);
447 JCheckBox currentColours = new JCheckBox();
449 JCheckBox thresholdIsMin = new JCheckBox();
451 JCheckBox seqAssociated = new JCheckBox();
453 public void minColour_actionPerformed()
455 Color col = JColorChooser.showDialog(this,
456 "Select Colour for Minimum Value", minColour.getBackground());
459 minColour.setBackground(col);
465 public void maxColour_actionPerformed()
467 Color col = JColorChooser.showDialog(this,
468 "Select Colour for Maximum Value", maxColour.getBackground());
471 maxColour.setBackground(col);
479 // Check if combobox is still adjusting
485 currentAnnotation = av.getAlignment().getAlignmentAnnotation()[annmap[annotations
486 .getSelectedIndex()]];
488 int aboveThreshold = -1;
489 if (threshold.getSelectedItem().equals("Above Threshold"))
491 aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
493 else if (threshold.getSelectedItem().equals("Below Threshold"))
495 aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
498 slider.setEnabled(true);
499 thresholdValue.setEnabled(true);
500 thresholdIsMin.setEnabled(true);
502 if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
504 slider.setEnabled(false);
505 thresholdValue.setEnabled(false);
506 thresholdValue.setText("");
507 thresholdIsMin.setEnabled(false);
509 else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
510 && currentAnnotation.threshold == null)
513 .setThreshold(new jalview.datamodel.GraphLine(
514 (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
515 "Threshold", Color.black));
518 if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
521 float range = currentAnnotation.graphMax * 1000
522 - currentAnnotation.graphMin * 1000;
524 slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
525 slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
526 slider.setValue((int) (currentAnnotation.threshold.value * 1000));
527 thresholdValue.setText(currentAnnotation.threshold.value + "");
528 slider.setMajorTickSpacing((int) (range / 10f));
529 slider.setEnabled(true);
530 thresholdValue.setEnabled(true);
534 AnnotationColourGradient acg = null;
535 if (currentColours.isSelected())
537 acg = new AnnotationColourGradient(currentAnnotation,
538 av.getGlobalColourScheme(), aboveThreshold);
542 acg = new AnnotationColourGradient(currentAnnotation,
543 minColour.getBackground(), maxColour.getBackground(),
546 acg.setSeqAssociated(seqAssociated.isSelected());
548 if (currentAnnotation.graphMin == 0f
549 && currentAnnotation.graphMax == 0f)
551 acg.predefinedColours = true;
554 acg.thresholdIsMinMax = thresholdIsMin.isSelected();
556 av.setGlobalColourScheme(acg);
558 if (av.getAlignment().getGroups() != null)
561 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
568 if (currentColours.isSelected())
570 sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
572 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
578 sg.cs = new AnnotationColourGradient(currentAnnotation,
579 minColour.getBackground(), maxColour.getBackground(),
581 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
587 ap.alignmentChanged();
588 // ensure all associated views (overviews, structures, etc) are notified of
590 ap.paintAlignment(true);
593 public void ok_actionPerformed(ActionEvent e)
598 frame.setClosed(true);
599 } catch (Exception ex)
604 public void cancel_actionPerformed(ActionEvent e)
607 // ensure all original colouring is propagated to listeners.
608 ap.paintAlignment(true);
611 frame.setClosed(true);
612 } catch (Exception ex)
619 av.setGlobalColourScheme(oldcs);
620 if (av.getAlignment().getGroups() != null)
623 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
625 sg.cs = (ColourSchemeI) oldgroupColours.get(sg);
630 public void thresholdCheck_actionPerformed(ActionEvent e)
635 public void annotations_actionPerformed(ActionEvent e)
640 public void threshold_actionPerformed(ActionEvent e)
645 public void thresholdValue_actionPerformed(ActionEvent e)
649 float f = Float.parseFloat(thresholdValue.getText());
650 slider.setValue((int) (f * 1000));
651 } catch (NumberFormatException ex)
656 public void valueChanged(boolean updateAllAnnotation)
658 if (currentColours.isSelected()
659 && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
663 currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
664 propagateSeqAssociatedThreshold(updateAllAnnotation);
665 ap.paintAlignment(false);
668 private void propagateSeqAssociatedThreshold(boolean allAnnotation)
670 if (currentAnnotation.sequenceRef == null
671 || currentAnnotation.threshold == null)
675 // TODO: JAL-1327 only update visible annotation thresholds if allAnnotation is false, since we only need to provide a quick visual indicator
677 float thr = currentAnnotation.threshold.value;
678 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
680 AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
681 if (aa.label.equals(currentAnnotation.label))
683 aa.threshold.value = thr;
688 public void currentColours_actionPerformed(ActionEvent e)
690 if (currentColours.isSelected())
695 maxColour.setEnabled(!currentColours.isSelected());
696 minColour.setEnabled(!currentColours.isSelected());
701 public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)