From 1c4d10234eab73bdc004335583c6ede0ebc95211 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Mon, 30 Oct 2017 16:57:24 +0000 Subject: [PATCH] JAL-2808 add attribute filter options to graduate colour dialog --- src/jalview/gui/FeatureColourChooser.java | 467 ++++++++++++++++++++++++----- 1 file changed, 385 insertions(+), 82 deletions(-) diff --git a/src/jalview/gui/FeatureColourChooser.java b/src/jalview/gui/FeatureColourChooser.java index d8db546..937b48e 100644 --- a/src/jalview/gui/FeatureColourChooser.java +++ b/src/jalview/gui/FeatureColourChooser.java @@ -22,19 +22,27 @@ package jalview.gui; import jalview.api.FeatureColourI; import jalview.datamodel.GraphLine; +import jalview.datamodel.features.FeatureAttributes; import jalview.schemes.FeatureColour; import jalview.util.MessageManager; +import jalview.util.matcher.Condition; +import jalview.util.matcher.KeyedMatcher; +import jalview.util.matcher.KeyedMatcherI; +import jalview.util.matcher.Matcher; +import jalview.util.matcher.MatcherI; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.Iterator; import javax.swing.BorderFactory; import javax.swing.JCheckBox; @@ -94,6 +102,18 @@ public class FeatureColourChooser extends JalviewDialog private ActionListener colourEditor = null; + private JComboBox filterAttribute; + + private JComboBox filterCondition; + + private JTextField filterValue; + + private JComboBox filterAttribute2; + + private JComboBox filterCondition2; + + private JTextField filterValue2; + /** * Constructor * @@ -213,62 +233,84 @@ public class FeatureColourChooser extends JalviewDialog threshline.value = cs.getThreshold(); } + setInitialFilters(cs.getAttributeFilters()); + adjusting = false; changeColour(false); waitForInput(); } - private void jbInit() throws Exception + /** + * Populates the attribute filter fields for the initial display + * + * @param attributeFilters + */ + void setInitialFilters(KeyedMatcherI attributeFilters) { - - minColour.setFont(JvSwingUtils.getLabelFont()); - minColour.setBorder(BorderFactory.createLineBorder(Color.black)); - minColour.setPreferredSize(new Dimension(40, 20)); - minColour.setToolTipText(MessageManager.getString("label.min_colour")); - minColour.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent e) + // todo generalise to populate N conditions + + if (attributeFilters != null) + { + filterAttribute.setSelectedItem(attributeFilters.getKey()); + filterCondition.setSelectedItem(attributeFilters.getMatcher() + .getCondition()); + filterValue.setText(attributeFilters.getMatcher().getPattern()); + + KeyedMatcherI second = attributeFilters.getSecondMatcher(); + if (second != null) { - if (minColour.isEnabled()) - { - minColour_actionPerformed(); - } + // todo add OR/AND condition to gui + filterAttribute2.setSelectedItem(second.getKey()); + filterCondition2 + .setSelectedItem(second.getMatcher().getCondition()); + filterValue2.setText(second.getMatcher().getPattern()); } - }); - maxColour.setFont(JvSwingUtils.getLabelFont()); - maxColour.setBorder(BorderFactory.createLineBorder(Color.black)); - maxColour.setPreferredSize(new Dimension(40, 20)); - maxColour.setToolTipText(MessageManager.getString("label.max_colour")); - maxColour.addMouseListener(new MouseAdapter() + } + } + + private void jbInit() throws Exception + { + this.setLayout(new GridLayout(4, 1)); + + JPanel colourByPanel = initColoursPanel(); + + JPanel thresholdPanel = initThresholdPanel(); + + JPanel okCancelPanel = initOkCancelPanel(); + + this.add(colourByPanel); + this.add(thresholdPanel); + + /* + * add filter by attributes options only if we know any attributes + */ + Iterator attributes = FeatureAttributes.getInstance() + .getAttributes(type).iterator(); + if (attributes.hasNext()) { - @Override - public void mousePressed(MouseEvent e) - { - if (maxColour.isEnabled()) - { - maxColour_actionPerformed(); - } - } - }); - maxColour.setBorder(new LineBorder(Color.black)); - JLabel minText = new JLabel(MessageManager.getString("label.min")); - minText.setFont(JvSwingUtils.getLabelFont()); - JLabel maxText = new JLabel(MessageManager.getString("label.max")); - maxText.setFont(JvSwingUtils.getLabelFont()); - this.setLayout(new BorderLayout()); - JPanel jPanel1 = new JPanel(); - jPanel1.setBackground(Color.white); - JPanel jPanel2 = new JPanel(); - jPanel2.setLayout(new FlowLayout()); - jPanel2.setBackground(Color.white); + JPanel filtersPanel = initFiltersPanel(attributes); + this.add(filtersPanel); + } + + this.add(okCancelPanel); + } + + /** + * Lay out fields for threshold options + * + * @return + */ + protected JPanel initThresholdPanel() + { + JPanel thresholdPanel = new JPanel(); + thresholdPanel.setLayout(new FlowLayout()); threshold.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - threshold_actionPerformed(); + changeColour(true); } }); threshold.setToolTipText(MessageManager @@ -280,8 +322,6 @@ public class FeatureColourChooser extends JalviewDialog threshold.addItem(MessageManager .getString("label.threshold_feature_below_threshold")); // index 2 - JPanel jPanel3 = new JPanel(); - jPanel3.setLayout(new FlowLayout()); thresholdValue.addActionListener(new ActionListener() { @Override @@ -308,7 +348,7 @@ public class FeatureColourChooser extends JalviewDialog MessageManager.getString("label.adjust_threshold")); thresholdValue.setEnabled(false); thresholdValue.setColumns(7); - jPanel3.setBackground(Color.white); + thresholdPanel.setBackground(Color.white); thresholdIsMin.setBackground(Color.white); thresholdIsMin .setText(MessageManager.getString("label.threshold_minmax")); @@ -319,40 +359,101 @@ public class FeatureColourChooser extends JalviewDialog @Override public void actionPerformed(ActionEvent actionEvent) { - thresholdIsMin_actionPerformed(); + changeColour(true); } }); - colourByLabel.setBackground(Color.white); - colourByLabel - .setText(MessageManager.getString("label.colour_by_label")); - colourByLabel.setToolTipText(MessageManager.getString( - "label.display_features_same_type_different_label_using_different_colour")); - colourByLabel.addActionListener(new ActionListener() + thresholdPanel.add(threshold); + thresholdPanel.add(slider); + thresholdPanel.add(thresholdValue); + thresholdPanel.add(thresholdIsMin); + return thresholdPanel; + } + + /** + * Lay out OK and Cancel buttons + * + * @return + */ + protected JPanel initOkCancelPanel() + { + JPanel okCancelPanel = new JPanel(); + okCancelPanel.setBackground(Color.white); + okCancelPanel.add(ok); + okCancelPanel.add(cancel); + return okCancelPanel; + } + + /** + * Lay out Colour by Label and min/max colour widgets + * + * @return + */ + protected JPanel initColoursPanel() + { + JPanel colourByPanel = new JPanel(); + colourByPanel.setLayout(new FlowLayout()); + colourByPanel.setBackground(Color.white); + minColour.setFont(JvSwingUtils.getLabelFont()); + minColour.setBorder(BorderFactory.createLineBorder(Color.black)); + minColour.setPreferredSize(new Dimension(40, 20)); + minColour.setToolTipText(MessageManager.getString("label.min_colour")); + minColour.addMouseListener(new MouseAdapter() { @Override - public void actionPerformed(ActionEvent actionEvent) + public void mousePressed(MouseEvent e) + { + if (minColour.isEnabled()) + { + minColour_actionPerformed(); + } + } + }); + maxColour.setFont(JvSwingUtils.getLabelFont()); + maxColour.setBorder(BorderFactory.createLineBorder(Color.black)); + maxColour.setPreferredSize(new Dimension(40, 20)); + maxColour.setToolTipText(MessageManager.getString("label.max_colour")); + maxColour.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent e) { - colourByLabel_actionPerformed(); + if (maxColour.isEnabled()) + { + maxColour_actionPerformed(); + } } }); + maxColour.setBorder(new LineBorder(Color.black)); + JLabel minText = new JLabel(MessageManager.getString("label.min")); + minText.setFont(JvSwingUtils.getLabelFont()); + JLabel maxText = new JLabel(MessageManager.getString("label.max")); + maxText.setFont(JvSwingUtils.getLabelFont()); JPanel colourPanel = new JPanel(); colourPanel.setBackground(Color.white); - jPanel1.add(ok); - jPanel1.add(cancel); - jPanel2.add(colourByLabel, BorderLayout.WEST); - jPanel2.add(colourPanel, BorderLayout.EAST); colourPanel.add(minText); colourPanel.add(minColour); colourPanel.add(maxText); colourPanel.add(maxColour); - this.add(jPanel3, BorderLayout.CENTER); - jPanel3.add(threshold); - jPanel3.add(slider); - jPanel3.add(thresholdValue); - jPanel3.add(thresholdIsMin); - this.add(jPanel1, BorderLayout.SOUTH); - this.add(jPanel2, BorderLayout.NORTH); + colourByPanel.add(colourByLabel, BorderLayout.WEST); + colourByPanel.add(colourPanel, BorderLayout.EAST); + + colourByLabel.setBackground(Color.white); + colourByLabel + .setText(MessageManager.getString("label.colour_by_label")); + colourByLabel + .setToolTipText(MessageManager + .getString("label.display_features_same_type_different_label_using_different_colour")); + colourByLabel.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent actionEvent) + { + changeColour(true); + } + }); + + return colourByPanel; } /** @@ -406,6 +507,11 @@ public class FeatureColourChooser extends JalviewDialog return; } + if (!validateInputs()) + { + return; + } + boolean aboveThreshold = false; boolean belowThreshold = false; if (threshold.getSelectedIndex() == 1) @@ -505,11 +611,100 @@ public class FeatureColourChooser extends JalviewDialog maxColour.setForeground(oldmaxColour); minColour.setForeground(oldminColour); } + + /* + * add attribute filters if entered + */ + if (filterAttribute != null) + { + setAttributeFilters(acg); + } + fr.setColour(type, acg); cs = acg; ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview); } + /** + * Checks inputs are valid, and answers true if they are, else false. Also + * sets the colour of invalid inputs to red. + * + * @return + */ + boolean validateInputs() + { + // todo generalise to N filters + return isValidFilter(filterValue, filterCondition) + || isValidFilter(filterValue2, filterCondition2); + } + + /** + * Answers true unless a numeric condition has been selected with a + * non-numeric value + * + * @param value + * @param condition + */ + protected boolean isValidFilter(JTextField value, JComboBox condition) + { + if (value == null || condition == null) + { + return true; // fields not populated + } + + value.setBackground(Color.white); + String v1 = value.getText().trim(); + if (v1.length() > 0) + { + Condition c1 = (Condition) condition.getSelectedItem(); + if (c1.isNumeric()) + { + try + { + Float.valueOf(v1); + } catch (NumberFormatException e) + { + value.setBackground(Color.red); + return false; + } + } + } + + return true; + } + + /** + * Sets any attribute value filters entered in the dialog as filters on the + * colour scheme + * + * @param acg + */ + protected void setAttributeFilters(FeatureColourI acg) + { + String attribute = (String) filterAttribute.getSelectedItem(); + Condition cond = (Condition) filterCondition.getSelectedItem(); + String pattern = filterValue.getText().trim(); + if (pattern.length() > 1) + { + MatcherI filter = new Matcher(cond, pattern); + KeyedMatcherI km = new KeyedMatcher(attribute, filter); + + /* + * is there a second condition? + * todo: generalise to N conditions + */ + pattern = filterValue2.getText().trim(); + if (pattern.length() > 1) + { + attribute = (String) filterAttribute2.getSelectedItem(); + cond = (Condition) filterCondition2.getSelectedItem(); + filter = new Matcher(cond, pattern); + km = km.and(attribute, filter); + } + acg.setAttributeFilters(km); + } + } + @Override protected void raiseClosed() { @@ -544,14 +739,6 @@ public class FeatureColourChooser extends JalviewDialog } /** - * Action on change of choice of No / Above / Below Threshold - */ - protected void threshold_actionPerformed() - { - changeColour(true); - } - - /** * Action on text entry of a threshold value */ protected void thresholdValue_actionPerformed() @@ -594,16 +781,6 @@ public class FeatureColourChooser extends JalviewDialog changeColour(false); } - protected void thresholdIsMin_actionPerformed() - { - changeColour(true); - } - - protected void colourByLabel_actionPerformed() - { - changeColour(true); - } - void addActionListener(ActionListener graduatedColorEditor) { if (colourEditor != null) @@ -629,4 +806,130 @@ public class FeatureColourChooser extends JalviewDialog return cs; } + /** + * Lay out fields for attribute value filters + * + * @param attNames + * + * @return + */ + protected JPanel initFiltersPanel(Iterator attNames) + { + JPanel filtersPanel = new JPanel(); + filtersPanel.setLayout(new GridLayout(2, 3)); + filtersPanel.setBackground(Color.white); + + /* + * drop-down choice of attribute + */ + filterAttribute = new JComboBox<>(); + filterAttribute2 = new JComboBox<>(); + while (attNames.hasNext()) + { + String attName = attNames.next(); + filterAttribute.addItem(attName); + filterAttribute2.addItem(attName); + } + filterAttribute.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + changeColour(true); + } + }); + + /* + * drop-down choice of test condition + */ + filterCondition = new JComboBox<>(); + for (Condition cond : Condition.values()) + { + filterCondition.addItem(cond); + } + filterCondition.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + changeColour(true); + } + }); + + filterValue = new JTextField(12); + filterValue.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + changeColour(true); + } + }); + filterValue.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + changeColour(true); + } + }); + + /* + * repeat for a second filter + * todo: generalise to N filters + */ + filterAttribute2.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + changeColour(true); + } + }); + + /* + * drop-down choice of test condition + */ + filterCondition2 = new JComboBox<>(); + for (Condition cond : Condition.values()) + { + filterCondition2.addItem(cond); + } + filterCondition2.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + changeColour(true); + } + }); + + filterValue2 = new JTextField(12); + filterValue2.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + changeColour(true); + } + }); + filterValue2.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + changeColour(true); + } + }); + + filtersPanel.add(filterAttribute); + filtersPanel.add(filterCondition); + filtersPanel.add(filterValue); + filtersPanel.add(filterAttribute2); + filtersPanel.add(filterCondition2); + filtersPanel.add(filterValue2); + + return filtersPanel; + } + } -- 1.7.10.2