2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
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 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/>.
17 * The Jalview Authors are detailed in the 'AUTHORS' file.
24 import java.awt.event.*;
27 import javax.swing.event.*;
29 import net.miginfocom.swing.MigLayout;
31 import jalview.bin.Cache;
32 import jalview.datamodel.*;
33 import jalview.schemes.*;
34 import java.awt.Dimension;
36 public class AnnotationColourChooser extends JPanel
46 Hashtable oldgroupColours;
48 jalview.datamodel.AlignmentAnnotation currentAnnotation;
50 boolean adjusting = false;
52 * enabled if the user is dragging the slider - try to keep updates to a minimun
54 boolean sliderDragging = false;
56 public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
58 oldcs = av.getGlobalColourScheme();
59 if (av.getAlignment().getGroups() != null)
61 oldgroupColours = new Hashtable();
62 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
66 oldgroupColours.put(sg, sg.cs);
72 frame = new JInternalFrame();
73 frame.setContentPane(this);
74 frame.setLayer(JLayeredPane.PALETTE_LAYER);
75 Desktop.addInternalFrame(frame, "Colour by Annotation", 520, 215);
77 slider.addChangeListener(new ChangeListener()
79 public void stateChanged(ChangeEvent evt)
83 thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
84 valueChanged(!sliderDragging);
88 slider.addMouseListener(new MouseAdapter()
91 public void mousePressed(MouseEvent e)
94 super.mousePressed(e);
98 public void mouseDragged(MouseEvent e)
101 super.mouseDragged(e);
103 public void mouseReleased(MouseEvent evt)
107 sliderDragging=false;
110 ap.paintAlignment(true);
114 if (av.getAlignment().getAlignmentAnnotation() == null)
119 // Always get default shading from preferences.
122 if (oldcs instanceof AnnotationColourGradient)
124 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
125 currentColours.setSelected(acg.predefinedColours);
126 if (!acg.predefinedColours)
128 minColour.setBackground(acg.getMinColour());
129 maxColour.setBackground(acg.getMaxColour());
131 seqAssociated.setSelected(acg.isSeqAssociated());
134 annotations = new JComboBox(
135 getAnnotationItems(seqAssociated.isSelected()));
137 threshold.addItem("No Threshold");
138 threshold.addItem("Above Threshold");
139 threshold.addItem("Below Threshold");
141 if (oldcs instanceof AnnotationColourGradient)
143 AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
144 annotations.setSelectedItem(acg.getAnnotation());
145 switch (acg.getAboveThreshold())
147 case AnnotationColourGradient.NO_THRESHOLD:
148 threshold.setSelectedItem("No Threshold");
150 case AnnotationColourGradient.ABOVE_THRESHOLD:
151 threshold.setSelectedItem("Above Threshold");
153 case AnnotationColourGradient.BELOW_THRESHOLD:
154 threshold.setSelectedItem("Below Threshold");
158 "Implementation error: don't know about threshold setting for current AnnotationColourGradient.");
160 thresholdIsMin.setSelected(acg.thresholdIsMinMax);
161 thresholdValue.setText("" + acg.getAnnotationThreshold());
167 } catch (Exception ex)
179 private Vector<String> getAnnotationItems(boolean isSeqAssociated)
181 Vector<String> list = new Vector<String>();
183 int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
184 boolean enableSeqAss = false;
185 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
187 if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
198 String label = av.getAlignment().getAlignmentAnnotation()[i].label;
199 if (!list.contains(label))
201 anmap[list.size()] = i;
202 list.addElement(label);
207 if (!isSeqAssociated)
209 anmap[list.size()] = i;
210 list.addElement(label + "_" + (index++));
214 seqAssociated.setEnabled(enableSeqAss);
215 annmap = new int[list.size()];
216 System.arraycopy(anmap, 0, annmap, 0, annmap.length);
219 private void setDefaultMinMax()
221 minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
223 maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
227 public AnnotationColourChooser()
232 } catch (Exception ex)
234 ex.printStackTrace();
238 private void jbInit() throws Exception
240 minColour.setFont(JvSwingUtils.getLabelFont());
241 minColour.setBorder(BorderFactory.createEtchedBorder());
242 minColour.setPreferredSize(new Dimension(40, 20));
243 minColour.setToolTipText("Minimum Colour");
244 minColour.addMouseListener(new MouseAdapter()
246 public void mousePressed(MouseEvent e)
248 if (minColour.isEnabled())
250 minColour_actionPerformed();
254 maxColour.setFont(JvSwingUtils.getLabelFont());
255 maxColour.setBorder(BorderFactory.createEtchedBorder());
256 maxColour.setPreferredSize(new Dimension(40, 20));
257 maxColour.setToolTipText("Maximum Colour");
258 maxColour.addMouseListener(new MouseAdapter()
260 public void mousePressed(MouseEvent e)
262 if (maxColour.isEnabled())
264 maxColour_actionPerformed();
270 ok.addActionListener(new ActionListener()
272 public void actionPerformed(ActionEvent e)
274 ok_actionPerformed(e);
277 cancel.setOpaque(false);
278 cancel.setText("Cancel");
279 cancel.addActionListener(new ActionListener()
281 public void actionPerformed(ActionEvent e)
283 cancel_actionPerformed(e);
286 defColours.setOpaque(false);
287 defColours.setText("Defaults");
289 .setToolTipText("Reset min and max colours to defaults from user preferences.");
290 defColours.addActionListener(new ActionListener()
294 public void actionPerformed(ActionEvent arg0)
296 resetColours_actionPerformed(arg0);
300 annotations.addActionListener(new ActionListener()
302 public void actionPerformed(ActionEvent e)
304 annotations_actionPerformed(e);
307 threshold.addActionListener(new ActionListener()
309 public void actionPerformed(ActionEvent e)
311 threshold_actionPerformed(e);
314 thresholdValue.addActionListener(new ActionListener()
316 public void actionPerformed(ActionEvent e)
318 thresholdValue_actionPerformed(e);
321 slider.setPaintLabels(false);
322 slider.setPaintTicks(true);
323 slider.setBackground(Color.white);
324 slider.setEnabled(false);
325 slider.setOpaque(false);
326 slider.setPreferredSize(new Dimension(100, 32));
327 thresholdValue.setEnabled(false);
328 thresholdValue.setColumns(7);
329 currentColours.setFont(JvSwingUtils.getLabelFont());
330 currentColours.setOpaque(false);
331 currentColours.setText("Use Original Colours");
332 currentColours.addActionListener(new ActionListener()
334 public void actionPerformed(ActionEvent e)
336 currentColours_actionPerformed(e);
339 thresholdIsMin.setBackground(Color.white);
340 thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
341 thresholdIsMin.setText("Threshold is Min/Max");
342 thresholdIsMin.addActionListener(new ActionListener()
344 public void actionPerformed(ActionEvent actionEvent)
346 thresholdIsMin_actionPerformed(actionEvent);
349 seqAssociated.setBackground(Color.white);
350 seqAssociated.setFont(JvSwingUtils.getLabelFont());
351 seqAssociated.setText("Per-sequence only");
352 seqAssociated.addActionListener(new ActionListener()
356 public void actionPerformed(ActionEvent arg0)
358 seqAssociated_actionPerformed(arg0);
362 this.setLayout(borderLayout1);
363 jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
364 jPanel1.setBackground(Color.white);
365 jPanel2.setBackground(Color.white);
369 jPanel2.add(annotations, "grow, wrap");
370 jPanel2.add(seqAssociated);
371 jPanel2.add(currentColours);
372 JPanel colpanel = new JPanel(new FlowLayout());
373 colpanel.setBackground(Color.white);
374 colpanel.add(minColour);
375 colpanel.add(maxColour);
376 jPanel2.add(colpanel, "wrap");
377 jPanel2.add(threshold);
378 jPanel2.add(defColours, "skip 1, wrap");
379 jPanel2.add(thresholdIsMin);
380 jPanel2.add(slider, "grow");
381 jPanel2.add(thresholdValue, "grow");
382 this.add(jPanel1, java.awt.BorderLayout.SOUTH);
383 this.add(jPanel2, java.awt.BorderLayout.CENTER);
387 protected void seqAssociated_actionPerformed(ActionEvent arg0)
390 String cursel = (String) annotations.getSelectedItem();
391 boolean isvalid = false, isseqs = seqAssociated.isSelected();
392 this.annotations.removeAllItems();
393 for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
395 if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
400 this.annotations.addItem(anitem);
405 this.annotations.setSelectedItem(cursel);
409 if (annotations.getItemCount() > 0)
411 annotations.setSelectedIndex(0);
416 protected void resetColours_actionPerformed(ActionEvent arg0)
422 JComboBox annotations;
426 JPanel minColour = new JPanel();
428 JPanel maxColour = new JPanel();
430 JButton defColours = new JButton();
432 JButton ok = new JButton();
434 JButton cancel = new JButton();
436 JPanel jPanel1 = new JPanel();
438 JPanel jPanel2 = new JPanel();
440 BorderLayout borderLayout1 = new BorderLayout();
442 JComboBox threshold = new JComboBox();
444 JSlider slider = new JSlider();
446 JTextField thresholdValue = new JTextField(20);
448 JCheckBox currentColours = new JCheckBox();
450 JCheckBox thresholdIsMin = new JCheckBox();
452 JCheckBox seqAssociated = new JCheckBox();
454 public void minColour_actionPerformed()
456 Color col = JColorChooser.showDialog(this,
457 "Select Colour for Minimum Value", minColour.getBackground());
460 minColour.setBackground(col);
466 public void maxColour_actionPerformed()
468 Color col = JColorChooser.showDialog(this,
469 "Select Colour for Maximum Value", maxColour.getBackground());
472 maxColour.setBackground(col);
480 // Check if combobox is still adjusting
486 currentAnnotation = av.getAlignment().getAlignmentAnnotation()[annmap[annotations
487 .getSelectedIndex()]];
489 int aboveThreshold = -1;
490 if (threshold.getSelectedItem().equals("Above Threshold"))
492 aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
494 else if (threshold.getSelectedItem().equals("Below Threshold"))
496 aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
499 slider.setEnabled(true);
500 thresholdValue.setEnabled(true);
501 thresholdIsMin.setEnabled(true);
503 if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
505 slider.setEnabled(false);
506 thresholdValue.setEnabled(false);
507 thresholdValue.setText("");
508 thresholdIsMin.setEnabled(false);
510 else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
511 && currentAnnotation.threshold == null)
514 .setThreshold(new jalview.datamodel.GraphLine(
515 (currentAnnotation.graphMax - currentAnnotation.graphMin) / 2f,
516 "Threshold", Color.black));
519 if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
522 float range = currentAnnotation.graphMax * 1000
523 - currentAnnotation.graphMin * 1000;
525 slider.setMinimum((int) (currentAnnotation.graphMin * 1000));
526 slider.setMaximum((int) (currentAnnotation.graphMax * 1000));
527 slider.setValue((int) (currentAnnotation.threshold.value * 1000));
528 thresholdValue.setText(currentAnnotation.threshold.value + "");
529 slider.setMajorTickSpacing((int) (range / 10f));
530 slider.setEnabled(true);
531 thresholdValue.setEnabled(true);
535 AnnotationColourGradient acg = null;
536 if (currentColours.isSelected())
538 acg = new AnnotationColourGradient(currentAnnotation,
539 av.getGlobalColourScheme(), aboveThreshold);
543 acg = new AnnotationColourGradient(currentAnnotation,
544 minColour.getBackground(), maxColour.getBackground(),
547 acg.setSeqAssociated(seqAssociated.isSelected());
549 if (currentAnnotation.graphMin == 0f
550 && currentAnnotation.graphMax == 0f)
552 acg.predefinedColours = true;
555 acg.thresholdIsMinMax = thresholdIsMin.isSelected();
557 av.setGlobalColourScheme(acg);
559 if (av.getAlignment().getGroups() != null)
562 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
569 if (currentColours.isSelected())
571 sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
573 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
579 sg.cs = new AnnotationColourGradient(currentAnnotation,
580 minColour.getBackground(), maxColour.getBackground(),
582 ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
588 ap.alignmentChanged();
589 // ensure all associated views (overviews, structures, etc) are notified of
591 ap.paintAlignment(true);
594 public void ok_actionPerformed(ActionEvent e)
599 frame.setClosed(true);
600 } catch (Exception ex)
605 public void cancel_actionPerformed(ActionEvent e)
608 // ensure all original colouring is propagated to listeners.
609 ap.paintAlignment(true);
612 frame.setClosed(true);
613 } catch (Exception ex)
620 av.setGlobalColourScheme(oldcs);
621 if (av.getAlignment().getGroups() != null)
624 for (SequenceGroup sg : ap.av.getAlignment().getGroups())
626 sg.cs = (ColourSchemeI) oldgroupColours.get(sg);
631 public void thresholdCheck_actionPerformed(ActionEvent e)
636 public void annotations_actionPerformed(ActionEvent e)
641 public void threshold_actionPerformed(ActionEvent e)
646 public void thresholdValue_actionPerformed(ActionEvent e)
650 float f = Float.parseFloat(thresholdValue.getText());
651 slider.setValue((int) (f * 1000));
652 } catch (NumberFormatException ex)
657 public void valueChanged(boolean updateAllAnnotation)
659 if (currentColours.isSelected()
660 && !(av.getGlobalColourScheme() instanceof AnnotationColourGradient))
664 currentAnnotation.threshold.value = (float) slider.getValue() / 1000f;
665 propagateSeqAssociatedThreshold(updateAllAnnotation);
666 ap.paintAlignment(false);
669 private void propagateSeqAssociatedThreshold(boolean allAnnotation)
671 if (currentAnnotation.sequenceRef == null
672 || currentAnnotation.threshold == null)
676 // TODO: JAL-1327 only update visible annotation thresholds if allAnnotation is false, since we only need to provide a quick visual indicator
678 float thr = currentAnnotation.threshold.value;
679 for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
681 AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
682 if (aa.label.equals(currentAnnotation.label))
684 aa.threshold.value = thr;
689 public void currentColours_actionPerformed(ActionEvent e)
691 if (currentColours.isSelected())
696 maxColour.setEnabled(!currentColours.isSelected());
697 minColour.setEnabled(!currentColours.isSelected());
702 public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)