X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAnnotationRowFilter.java;h=44a16683651634b54ca39a690c364318f91c1bea;hb=57738a1f3c19b1c3a00bd3ac5108f8cd0af32f99;hp=1b036c16a8bced406812b2dcc722ff3a947846ac;hpb=c5cece0a9d56e59293c8e6497b5afa6e26842646;p=jalview.git diff --git a/src/jalview/gui/AnnotationRowFilter.java b/src/jalview/gui/AnnotationRowFilter.java index 1b036c1..44a1668 100644 --- a/src/jalview/gui/AnnotationRowFilter.java +++ b/src/jalview/gui/AnnotationRowFilter.java @@ -22,14 +22,23 @@ package jalview.gui; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.GraphLine; -import jalview.datamodel.SequenceGroup; import jalview.schemes.AnnotationColourGradient; import jalview.util.MessageManager; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.HashMap; +import java.util.Map; import java.util.Vector; import javax.swing.JButton; @@ -37,7 +46,6 @@ import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JInternalFrame; import javax.swing.JPanel; -import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -45,29 +53,23 @@ import javax.swing.event.ChangeListener; @SuppressWarnings("serial") public abstract class AnnotationRowFilter extends JPanel { + private static final String TWO_DP = "%.2f"; + + private final static MathContext FOUR_SIG_FIG = new MathContext(4); + protected AlignViewport av; protected AlignmentPanel ap; protected int[] annmap; - protected boolean enableSeqAss = false; - - private AlignmentAnnotation currentAnnotation; - protected boolean adjusting = false; - protected JCheckBox currentColours = new JCheckBox(); - - protected JPanel minColour = new JPanel(); - - protected JPanel maxColour = new JPanel(); - protected JCheckBox seqAssociated = new JCheckBox(); - protected JCheckBox thresholdIsMin = new JCheckBox(); + protected JCheckBox percentThreshold = new JCheckBox(); - protected JSlider slider = new JSlider(); + protected Slider slider; protected JTextField thresholdValue = new JTextField(20); @@ -83,6 +85,41 @@ public abstract class AnnotationRowFilter extends JPanel */ protected boolean sliderDragging = false; + protected JComboBox threshold = new JComboBox<>(); + + protected JComboBox annotations; + + /* + * map from annotation to its menu item display label + * - so we know which item to pre-select on restore + */ + private Map annotationLabels; + + private AlignmentAnnotation currentAnnotation; + + /** + * Constructor + * + * @param viewport + * @param alignPanel + */ + public AnnotationRowFilter(AlignViewport viewport, + final AlignmentPanel alignPanel) + { + this.av = viewport; + this.ap = alignPanel; + this.slider = new Slider(0f, 100f, 50f); + + thresholdValue.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + thresholdValue_actionPerformed(); + } + }); + } + protected void addSliderChangeListener() { @@ -93,13 +130,80 @@ public abstract class AnnotationRowFilter extends JPanel { if (!adjusting) { - thresholdValue.setText((slider.getValue() / 1000f) + ""); + setThresholdValueText(); valueChanged(!sliderDragging); } } }); } + /** + * update the text field from the threshold slider. preserves state of + * 'adjusting' so safe to call in init. + */ + protected void setThresholdValueText() + { + boolean oldadj = adjusting; + adjusting = true; + if (percentThreshold.isSelected()) + { + thresholdValue + .setText(String.format(TWO_DP, getSliderPercentageValue())); + } + else + { + /* + * round to 4 significant digits without trailing zeroes + */ + float f = getSliderValue(); + BigDecimal formatted = new BigDecimal(f).round(FOUR_SIG_FIG) + .stripTrailingZeros(); + thresholdValue.setText(formatted.toPlainString()); + } + adjusting = oldadj; + } + + /** + * Answers the value of the slider position (descaled to 'true' value) + * + * @return + */ + protected float getSliderValue() + { + return slider.getSliderValue(); + } + + /** + * Sets the slider value (scaled from the true value to the slider range) + * + * @param value + */ + protected void setSliderValue(float value) + { + slider.setSliderValue(value); + } + + /** + * Answers the value of the slider position as a percentage between minimum + * and maximum of its range + * + * @return + */ + protected float getSliderPercentageValue() + { + return slider.getSliderPercentageValue(); + } + + /** + * Sets the slider position for a given percentage value of its min-max range + * + * @param pct + */ + protected void setSliderPercentageValue(float pct) + { + slider.setSliderPercentageValue(pct); + } + protected void addSliderMouseListeners() { @@ -122,43 +226,34 @@ public abstract class AnnotationRowFilter extends JPanel @Override public void mouseReleased(MouseEvent evt) { - if (sliderDragging) - { - sliderDragging = false; - valueChanged(true); - } - ap.paintAlignment(true); - } - }); - } - - public AnnotationRowFilter(AlignViewport av, final AlignmentPanel ap) - { - this.av = av; - this.ap = ap; - thresholdValue.addFocusListener(new FocusAdapter() - { - @Override - public void focusLost(FocusEvent e) - { - thresholdValue_actionPerformed(); + sliderDragReleased(); } }); } - public AnnotationRowFilter() - { - - } - + /** + * Builds and returns a list of menu items (display text) for choice of + * annotation. Also builds maps between annotations, their positions in the + * list, and their display labels in the list. + * + * @param isSeqAssociated + * @return + */ public Vector getAnnotationItems(boolean isSeqAssociated) { - Vector list = new Vector(); + annotationLabels = new HashMap<>(); + + Vector list = new Vector<>(); int index = 1; - int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length]; - for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++) + int[] anmap = new int[av.getAlignment() + .getAlignmentAnnotation().length]; + seqAssociated.setEnabled(false); + for (int i = 0; i < av.getAlignment() + .getAlignmentAnnotation().length; i++) { - if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null) + AlignmentAnnotation annotation = av.getAlignment() + .getAlignmentAnnotation()[i]; + if (annotation.sequenceRef == null) { if (isSeqAssociated) { @@ -167,30 +262,29 @@ public abstract class AnnotationRowFilter extends JPanel } else { - enableSeqAss = true; + seqAssociated.setEnabled(true); } - String label = av.getAlignment().getAlignmentAnnotation()[i].label; + String label = annotation.label; // add associated sequence ID if available - if (!isSeqAssociated - && av.getAlignment().getAlignmentAnnotation()[i].sequenceRef != null) + if (!isSeqAssociated && annotation.sequenceRef != null) { - label = label - + "_" - + av.getAlignment().getAlignmentAnnotation()[i].sequenceRef - .getName(); + label = label + "_" + annotation.sequenceRef.getName(); } // make label unique if (!list.contains(label)) { anmap[list.size()] = i; list.add(label); + annotationLabels.put(annotation, label); } else { if (!isSeqAssociated) { anmap[list.size()] = i; - list.add(label + "_" + (index++)); + label = label + "_" + (index++); + list.add(label); + annotationLabels.put(annotation, label); } } } @@ -213,11 +307,6 @@ public abstract class AnnotationRowFilter extends JPanel return selectedThresholdItem; } - public void modelChanged() - { - seqAssociated.setEnabled(enableSeqAss); - } - public void ok_actionPerformed() { try @@ -231,7 +320,7 @@ public abstract class AnnotationRowFilter extends JPanel public void cancel_actionPerformed() { reset(); - ap.paintAlignment(true); + ap.paintAlignment(true, true); try { frame.setClosed(true); @@ -240,54 +329,77 @@ public abstract class AnnotationRowFilter extends JPanel } } - public void thresholdCheck_actionPerformed() + protected void thresholdCheck_actionPerformed() { updateView(); } - public void annotations_actionPerformed() + protected void selectedAnnotationChanged() { updateView(); } - public void threshold_actionPerformed() + protected void threshold_actionPerformed() { updateView(); } - public void thresholdValue_actionPerformed() + /** + * Updates the slider position, and the display, for an update in the slider's + * text input field + */ + protected void thresholdValue_actionPerformed() { try { float f = Float.parseFloat(thresholdValue.getText()); - slider.setValue((int) (f * 1000)); + if (percentThreshold.isSelected()) + { + setSliderPercentageValue(f); + } + else + { + setSliderValue(f); + } updateView(); } catch (NumberFormatException ex) { } } - public void thresholdIsMin_actionPerformed() + protected void percentageValue_actionPerformed() + { + setThresholdValueText(); + } + + protected void thresholdIsMin_actionPerformed() { updateView(); } - protected void populateThresholdComboBox(JComboBox threshold) + protected void populateThresholdComboBox(JComboBox thresh) { - threshold.addItem(MessageManager + thresh.addItem(MessageManager .getString("label.threshold_feature_no_threshold")); - threshold.addItem(MessageManager + thresh.addItem(MessageManager .getString("label.threshold_feature_above_threshold")); - threshold.addItem(MessageManager + thresh.addItem(MessageManager .getString("label.threshold_feature_below_threshold")); } - protected void seqAssociated_actionPerformed(JComboBox annotations) + /** + * Rebuilds the drop-down list of annotations to choose from when the 'per + * sequence only' checkbox is checked or unchecked. + * + * @param anns + */ + protected void seqAssociated_actionPerformed(JComboBox anns) { adjusting = true; - String cursel = (String) annotations.getSelectedItem(); - boolean isvalid = false, isseqs = seqAssociated.isSelected(); - annotations.removeAllItems(); + String cursel = (String) anns.getSelectedItem(); + boolean isvalid = false; + boolean isseqs = seqAssociated.isSelected(); + anns.removeAllItems(); for (String anitem : getAnnotationItems(seqAssociated.isSelected())) { if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem))) @@ -295,20 +407,22 @@ public abstract class AnnotationRowFilter extends JPanel isvalid = true; cursel = anitem; } - annotations.addItem(anitem); + anns.addItem(anitem); } - adjusting = false; if (isvalid) { - annotations.setSelectedItem(cursel); + anns.setSelectedItem(cursel); } else { - if (annotations.getItemCount() > 0) + if (anns.getItemCount() > 0) { - annotations.setSelectedIndex(0); + anns.setSelectedIndex(0); } } + adjusting = false; + + updateView(); } protected void propagateSeqAssociatedThreshold(boolean allAnnotation, @@ -320,9 +434,11 @@ public abstract class AnnotationRowFilter extends JPanel } float thr = annotation.threshold.value; - for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++) + for (int i = 0; i < av.getAlignment() + .getAlignmentAnnotation().length; i++) { - AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i]; + AlignmentAnnotation aa = av.getAlignment() + .getAlignmentAnnotation()[i]; if (aa.label.equals(annotation.label) && (annotation.getCalcId() == null ? aa.getCalcId() == null : annotation.getCalcId().equals(aa.getCalcId()))) @@ -339,79 +455,153 @@ public abstract class AnnotationRowFilter extends JPanel } } - protected boolean colorAlignmContaining(AlignmentAnnotation currentAnn, - int selectedThresholdOption) + public AlignmentAnnotation getCurrentAnnotation() { + return currentAnnotation; + } - AnnotationColourGradient acg = null; - if (currentColours.isSelected()) - { - acg = new AnnotationColourGradient(currentAnn, - av.getGlobalColourScheme(), selectedThresholdOption); - } - else + protected void setCurrentAnnotation(AlignmentAnnotation annotation) + { + this.currentAnnotation = annotation; + } + + /** + * update associated view model and trigger any necessary repaints. + * + * @param updateAllAnnotation + */ + protected abstract void valueChanged(boolean updateAllAnnotation); + + protected abstract void updateView(); + + protected abstract void reset(); + + protected String getAnnotationMenuLabel(AlignmentAnnotation ann) + { + return annotationLabels.get(ann); + } + + protected void jbInit() + { + ok.setOpaque(false); + ok.setText(MessageManager.getString("action.ok")); + ok.addActionListener(new ActionListener() { - acg = new AnnotationColourGradient(currentAnn, - minColour.getBackground(), maxColour.getBackground(), - selectedThresholdOption); - } - acg.setSeqAssociated(seqAssociated.isSelected()); + @Override + public void actionPerformed(ActionEvent e) + { + ok_actionPerformed(); + } + }); - if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f) + cancel.setOpaque(false); + cancel.setText(MessageManager.getString("action.cancel")); + cancel.addActionListener(new ActionListener() { - acg.setPredefinedColours(true); - } + @Override + public void actionPerformed(ActionEvent e) + { + cancel_actionPerformed(); + } + }); - acg.thresholdIsMinMax = thresholdIsMin.isSelected(); + annotations.addItemListener(new ItemListener() + { + @Override + public void itemStateChanged(ItemEvent e) + { + selectedAnnotationChanged(); + } + }); + annotations.setToolTipText( + MessageManager.getString("info.select_annotation_row")); - av.setGlobalColourScheme(acg); + threshold.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + threshold_actionPerformed(); + } + }); - if (av.getAlignment().getGroups() != null) + thresholdValue.setEnabled(false); + thresholdValue.setColumns(7); + thresholdValue.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) + { + thresholdValue_actionPerformed(); + } + }); - for (SequenceGroup sg : ap.av.getAlignment().getGroups()) + percentThreshold + .setText(MessageManager.getString("label.as_percentage")); + percentThreshold.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) { - if (sg.cs == null) + if (!adjusting) { - continue; + percentageValue_actionPerformed(); } + } + }); + slider.setPaintLabels(false); + slider.setPaintTicks(true); + slider.setBackground(Color.white); + slider.setEnabled(false); + slider.setOpaque(false); + slider.setPreferredSize(new Dimension(100, 32)); + } - if (currentColours.isSelected()) - { - sg.cs = new AnnotationColourGradient(currentAnn, sg.cs, - selectedThresholdOption); - ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated - .isSelected()); - - } - else - { - sg.cs = new AnnotationColourGradient(currentAnn, - minColour.getBackground(), maxColour.getBackground(), - selectedThresholdOption); - ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated - .isSelected()); - } + public JComboBox getThreshold() + { + return threshold; + } - } - } - return false; + public void setThreshold(JComboBox thresh) + { + this.threshold = thresh; } - public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation() + public JComboBox getAnnotations() { - return currentAnnotation; + return annotations; } - public void setCurrentAnnotation( - jalview.datamodel.AlignmentAnnotation currentAnnotation) + public void setAnnotations(JComboBox anns) { - this.currentAnnotation = currentAnnotation; + this.annotations = anns; } - public abstract void valueChanged(boolean updateAllAnnotation); + protected void sliderDragReleased() + { + if (sliderDragging) + { + sliderDragging = false; + valueChanged(true); + } + } - public abstract void updateView(); + /** + * Sets the min-max range and current value of the slider, with rescaling from + * true values to slider range as required + * + * @param min + * @param max + * @param value + */ + protected void setSliderModel(float min, float max, float value) + { + slider.setSliderModel(min, max, value); - public abstract void reset(); + /* + * tick mark every 10th position + */ + slider.setMajorTickSpacing( + (slider.getMaximum() - slider.getMinimum()) / 10); + } }