X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=inline;f=src%2Fjalview%2Fgui%2FFeatureTypeSettings.java;h=50efffc479d06a12772bca765d25c4cb786e239e;hb=91e47ada7d1216e06dfcf2c32c7d2be396654455;hp=0b8b2b2922e9dcc8c2662dd98fa1fcfc50e6beba;hpb=a7640c4b1d23de78b3fdd2f758260a4eb7c240e7;p=jalview.git diff --git a/src/jalview/gui/FeatureTypeSettings.java b/src/jalview/gui/FeatureTypeSettings.java index 0b8b2b2..50efffc 100644 --- a/src/jalview/gui/FeatureTypeSettings.java +++ b/src/jalview/gui/FeatureTypeSettings.java @@ -22,6 +22,7 @@ package jalview.gui; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureColourI; +import jalview.bin.Cache; import jalview.datamodel.GraphLine; import jalview.datamodel.features.FeatureAttributes; import jalview.datamodel.features.FeatureAttributes.Datatype; @@ -30,6 +31,7 @@ import jalview.datamodel.features.FeatureMatcherI; import jalview.datamodel.features.FeatureMatcherSet; import jalview.datamodel.features.FeatureMatcherSetI; import jalview.io.gff.SequenceOntologyFactory; +import jalview.io.gff.SequenceOntologyI; import jalview.schemes.FeatureColour; import jalview.util.ColorUtils; import jalview.util.MessageManager; @@ -51,6 +53,7 @@ import java.awt.event.MouseEvent; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -68,11 +71,10 @@ import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JTextField; -import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import javax.swing.plaf.basic.BasicArrowButton; /** * A dialog where the user can configure colour scheme, and any filters, for one @@ -172,7 +174,7 @@ public class FeatureTypeSettings extends JalviewDialog private JPanel maxColour = new JPanel(); - private JComboBox threshold = new JComboBox<>(); + private JComboBox threshold = new JComboBox<>(); private JSlider slider = new JSlider(); @@ -189,17 +191,17 @@ public class FeatureTypeSettings extends JalviewDialog /* * choice of option for 'colour for no value' */ - private JComboBox noValueCombo; + private JComboBox noValueCombo; /* * choice of what to colour by text (Label or attribute) */ - private JComboBox colourByTextCombo; + private JComboBox colourByTextCombo; /* * choice of what to colour by range (Score or attribute) */ - private JComboBox colourByRangeCombo; + private JComboBox colourByRangeCombo; private JRadioButton andFilters; @@ -213,19 +215,30 @@ public class FeatureTypeSettings extends JalviewDialog private JPanel chooseFiltersPanel; /* - * feature types present in Feature Renderer which are - * sub-types of the one this editor is acting on + * the root Sequence Ontology terms (if any) that is a parent of + * the current feature type */ - private final List subTypes; + private String rootSOTerm; + + /* + * a map whose keys are Sequence Ontology terms - selected from the + * current term and its parents in the SO - whose subterms include + * additional feature types; the map entry is the list of additional + * feature types that match the key or have it as a parent term; in + * other words, distinct 'aggregations' that include the current feature type + */ + private final Map> relatedSoTerms; /* * if true, filter or colour settings are also applied to - * any feature sub-types in the Sequence Ontology + * any sub-types of parentTerm in the Sequence Ontology */ private boolean applyFiltersToSubtypes; private boolean applyColourToSubtypes; + private String parentSOTerm; + /** * Constructor * @@ -238,30 +251,29 @@ public class FeatureTypeSettings extends JalviewDialog this.featureType = theType; ap = fr.ap; - /* - * determine sub-types (if any) of this feature type - */ - List types = fr.getRenderOrder(); - subTypes = SequenceOntologyFactory.getInstance() - .getChildTerms(this.featureType, types); - Collections.sort(subTypes); // sort for ease of reading in tooltip + SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + relatedSoTerms = so.findSequenceOntologyGroupings( + this.featureType, fr.getRenderOrder()); /* - * save original colours and filters for this feature type - * and any sub-types, to restore on Cancel + * save original colours and filters for this feature type, + * and any related types, to restore on Cancel */ originalFilters = new HashMap<>(); originalFilters.put(theType, fr.getFeatureFilter(theType)); originalColours = new HashMap<>(); originalColours.put(theType, fr.getFeatureColours().get(theType)); - for (String child : subTypes) + for (List related : relatedSoTerms.values()) { - originalFilters.put(child, fr.getFeatureFilter(child)); - originalColours.put(child, fr.getFeatureColours().get(child)); + for (String type : related) + { + originalFilters.put(type, fr.getFeatureFilter(type)); + originalColours.put(type, fr.getFeatureColours().get(type)); + } } adjusting = true; - + try { initialise(); @@ -270,15 +282,15 @@ public class FeatureTypeSettings extends JalviewDialog ex.printStackTrace(); return; } - + updateColoursTab(); - + updateFiltersTab(); - + adjusting = false; - + colourChanged(false); - + String title = MessageManager .formatMessage("label.display_settings_for", new String[] { theType }); @@ -287,6 +299,60 @@ public class FeatureTypeSettings extends JalviewDialog } /** + * Answers a (possibly empty) map of any Sequence Ontology terms (the current + * feature type and its parents) which incorporate additional known feature + * types (the map entry). + *

+ * For example if {@code stop_gained} and {@code stop_lost} are known feature + * types, then SO term {@ nonsynonymous_variant} is the first common parent of + * both terms + * + * @param featureType + * the current feature type being configured + * @param featureTypes + * all known feature types on the alignment + * @return + */ + protected static Map> findSequenceOntologyGroupings( + String featureType, List featureTypes) + { + List sortedTypes = new ArrayList<>(featureTypes); + Collections.sort(sortedTypes); + + Map> parents = new HashMap<>(); + + /* + * method: + * walk up featureType and all of its parents + * find other feature types which are subsumed by each term + * add each distinct aggregation of included feature types to the map + */ + List candidates = new ArrayList<>(); + SequenceOntologyI so = SequenceOntologyFactory.getInstance(); + candidates.add(featureType); + while (!candidates.isEmpty()) + { + String term = candidates.remove(0); + List includedFeatures = new ArrayList<>(); + for (String type : sortedTypes) + { + if (!type.equals(featureType) && so.isA(type, term)) + { + includedFeatures.add(type); + } + } + if (!includedFeatures.isEmpty() + && !parents.containsValue(includedFeatures)) + { + parents.put(term, includedFeatures); + } + candidates.addAll(so.getParents(term)); + } + + return parents; + } + + /** * Configures the widgets on the Colours tab according to the current feature * colour scheme */ @@ -771,9 +837,9 @@ public class FeatureTypeSettings extends JalviewDialog MessageManager.getString("action.colour"), true); /* - * option to apply colour to sub-types as well (if there are any) + * option to apply colour to other selected types as well */ - if (!subTypes.isEmpty()) + if (!relatedSoTerms.isEmpty()) { applyColourToSubtypes = false; colourByPanel.add(initSubtypesPanel(false)); @@ -878,8 +944,8 @@ public class FeatureTypeSettings extends JalviewDialog } /** - * Constructs and returns a panel with a checkbox for the option to apply any - * changes also to sub-types of the feature type + * Constructs and returns a panel with the option to apply any changes also to + * sub-types of SO terms at or above the feature type * * @return */ @@ -887,10 +953,48 @@ public class FeatureTypeSettings extends JalviewDialog { JPanel toSubtypes = new JPanel(new FlowLayout(FlowLayout.LEFT)); toSubtypes.setBackground(Color.WHITE); + + /* + * checkbox 'apply to sub-types of...' + */ JCheckBox applyToSubtypesCB = new JCheckBox(MessageManager - .formatMessage("label.apply_to_subtypes", featureType)); - applyToSubtypesCB.setToolTipText(getSubtypesTooltip()); - applyToSubtypesCB.addActionListener(new ActionListener() + .formatMessage("label.apply_to_subtypes", rootSOTerm)); + toSubtypes.add(applyToSubtypesCB); + toSubtypes + .setToolTipText(MessageManager.getString("label.group_by_so")); + + /* + * combobox to choose 'parent' of sub-types + */ + List soTerms = new ArrayList<>(); + for (String term : relatedSoTerms.keySet()) + { + soTerms.add(term); + } + // sort from most restrictive to most inclusive + Collections.sort(soTerms, new Comparator() + { + @Override + public int compare(String o1, String o2) + { + return Integer.compare(relatedSoTerms.get(o1).size(), + relatedSoTerms.get(o2).size()); + } + }); + List tooltips = new ArrayList<>(); + for (String term : soTerms) + { + tooltips.add(getSOTermsTooltip(relatedSoTerms.get(term))); + } + JComboBox parentType = JvSwingUtils + .buildComboWithTooltips(soTerms, tooltips); + toSubtypes.add(parentType); + + /* + * on toggle of checkbox, or change of parent SO term, + * reset and then reapply filters to the selected scope + */ + final ActionListener action = new ActionListener() { /* * reset and reapply settings on toggle of checkbox @@ -898,6 +1002,7 @@ public class FeatureTypeSettings extends JalviewDialog @Override public void actionPerformed(ActionEvent e) { + parentSOTerm = (String) parentType.getSelectedItem(); if (forFilters) { applyFiltersToSubtypes = applyToSubtypesCB.isSelected(); @@ -911,8 +1016,9 @@ public class FeatureTypeSettings extends JalviewDialog colourChanged(true); } } - }); - toSubtypes.add(applyToSubtypesCB); + }; + applyToSubtypesCB.addActionListener(action); + parentType.addActionListener(action); return toSubtypes; } @@ -961,7 +1067,7 @@ public class FeatureTypeSettings extends JalviewDialog fr.setColour(featureType, acg); if (applyColourToSubtypes) { - for (String child : subTypes) + for (String child : relatedSoTerms.get(parentSOTerm)) { fr.setColour(child, acg); } @@ -1115,6 +1221,10 @@ public class FeatureTypeSettings extends JalviewDialog ap.paintAlignment(true, true); } + /** + * Restores filters for all feature types to their values when the dialog was + * opened + */ protected void restoreOriginalFilters() { for (Entry entry : originalFilters @@ -1124,6 +1234,10 @@ public class FeatureTypeSettings extends JalviewDialog } } + /** + * Restores colours for all feature types to their values when the dialog was + * opened + */ protected void restoreOriginalColours() { for (Entry entry : originalColours.entrySet()) @@ -1145,7 +1259,7 @@ public class FeatureTypeSettings extends JalviewDialog */ adjusting = true; float f = Float.parseFloat(thresholdValue.getText()); - f = Float.max(f, this.min); + f = Float.max(f, this.min); f = Float.min(f, this.max); thresholdValue.setText(String.valueOf(f)); slider.setValue((int) (f * scaleFactor)); @@ -1220,7 +1334,7 @@ public class FeatureTypeSettings extends JalviewDialog * @param withRange * @param withText */ - protected JComboBox populateAttributesDropdown( + protected JComboBox populateAttributesDropdown( List attNames, boolean withRange, boolean withText) { List displayAtts = new ArrayList<>(); @@ -1259,9 +1373,11 @@ public class FeatureTypeSettings extends JalviewDialog tooltips.add(desc == null ? "" : desc); } - JComboBox attCombo = JvSwingUtils - .buildComboWithTooltips(displayAtts, tooltips); - + // now convert String List to Object List for buildComboWithTooltips + List displayAttsObjects = new ArrayList<>(displayAtts); + JComboBox attCombo = JvSwingUtils + .buildComboWithTooltips(displayAttsObjects, tooltips); + return attCombo; } @@ -1277,9 +1393,9 @@ public class FeatureTypeSettings extends JalviewDialog outerPanel.setBackground(Color.white); /* - * option to apply colour to sub-types as well (if there are any) + * option to apply colour to other selected types as well */ - if (!subTypes.isEmpty()) + if (!relatedSoTerms.isEmpty()) { applyFiltersToSubtypes = false; outerPanel.add(initSubtypesPanel(true)); @@ -1316,10 +1432,6 @@ public class FeatureTypeSettings extends JalviewDialog JPanel andOrPanel = new JPanel(new BorderLayout()); andOrPanel.setBackground(Color.white); -// JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); -// andOrPanel.add(panel1, BorderLayout.WEST); -// panel1.setBackground(Color.white); -// panel1.setBorder(BorderFactory.createLineBorder(debugBorderColour)); andFilters = new JRadioButton(MessageManager.getString("label.and")); orFilters = new JRadioButton(MessageManager.getString("label.or")); ActionListener actionListener = new ActionListener() @@ -1345,16 +1457,18 @@ public class FeatureTypeSettings extends JalviewDialog } /** - * Builds a tooltip for the 'Apply to subtypes' checkbox with a list of - * subtypes of this feature type + * Builds a tooltip for the 'Apply also to...' combobox with a list of known + * feature types (excluding the current type) which are sub-types of the + * selected Sequence Ontology term * + * @param * @return */ - protected String getSubtypesTooltip() + protected String getSOTermsTooltip(List list) { - StringBuilder sb = new StringBuilder(20 * subTypes.size()); + StringBuilder sb = new StringBuilder(20 * relatedSoTerms.size()); sb.append(MessageManager.getString("label.apply_also_to")); - for (String child : subTypes) + for (String child : list) { sb.append("
").append(child); } @@ -1470,7 +1584,7 @@ public class FeatureTypeSettings extends JalviewDialog * drop-down choice of attribute, with description as a tooltip * if we can obtain it */ - final JComboBox attCombo = populateAttributesDropdown(attNames, + final JComboBox attCombo = populateAttributesDropdown(attNames, true, true); String filterBy = setSelectedAttribute(attCombo, filter); @@ -1572,10 +1686,10 @@ public class FeatureTypeSettings extends JalviewDialog if (!patternField.isEnabled() || (pattern != null && pattern.trim().length() > 0)) { - // todo: gif for button drawing '-' or 'x' - JButton removeCondition = new BasicArrowButton(SwingConstants.WEST); - removeCondition - .setToolTipText(MessageManager.getString("label.delete_row")); + JButton removeCondition = new JButton("\u2717"); // Dingbats cursive x + removeCondition.setToolTipText( + MessageManager.getString("label.delete_condition")); + removeCondition.setBorder(new EmptyBorder(0, 0, 0, 0)); removeCondition.addActionListener(new ActionListener() { @Override @@ -1598,7 +1712,7 @@ public class FeatureTypeSettings extends JalviewDialog * @param attCombo * @param filter */ - private String setSelectedAttribute(JComboBox attCombo, + private String setSelectedAttribute(JComboBox attCombo, FeatureMatcherI filter) { String item = null; @@ -1815,11 +1929,19 @@ public class FeatureTypeSettings extends JalviewDialog * @param valueField * @param filterIndex */ - protected boolean updateFilter(JComboBox attCombo, + protected boolean updateFilter(JComboBox attCombo, JComboBox condCombo, JTextField valueField, int filterIndex) { - String attName = (String) attCombo.getSelectedItem(); + String attName; + try + { + attName = (String) attCombo.getSelectedItem(); + } catch (Exception e) + { + Cache.log.error("Problem casting Combo box entry to String"); + attName = attCombo.getSelectedItem().toString(); + } Condition cond = (Condition) condCombo.getSelectedItem(); String pattern = valueField.getText().trim(); @@ -1898,7 +2020,7 @@ public class FeatureTypeSettings extends JalviewDialog fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined); if (applyFiltersToSubtypes) { - for (String child : subTypes) + for (String child : relatedSoTerms.get(parentSOTerm)) { fr.setFeatureFilter(child, combined.isEmpty() ? null : combined); }