X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fviewmodel%2Fseqfeatures%2FFeatureRendererModel.java;h=5923e1ff831e1257b7713bba77b457d7a0885de1;hb=4435c731351c802772dd1355fdb5747cfacd7838;hp=c2f5bb76c1af4a4cd0783da09548831a46727bc2;hpb=9feb54a4d32293b760afcdc29672fb6a880c6cbb;p=jalview.git diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index c2f5bb7..5923e1f 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -26,17 +26,18 @@ import jalview.api.FeaturesDisplayedI; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.datamodel.features.FeatureMatcherSetI; import jalview.datamodel.features.SequenceFeatures; import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.schemes.FeatureColour; import jalview.util.ColorUtils; -import jalview.util.matcher.KeyedMatcherSetI; import java.awt.Color; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -49,6 +50,28 @@ import java.util.concurrent.ConcurrentHashMap; public abstract class FeatureRendererModel implements jalview.api.FeatureRenderer { + /* + * a data bean to hold one row of feature settings from the gui + */ + public static class FeatureSettingsBean + { + public final String featureType; + + public final FeatureColourI featureColour; + + public final FeatureMatcherSetI filter; + + public final Boolean show; + + public FeatureSettingsBean(String type, FeatureColourI colour, + FeatureMatcherSetI theFilter, Boolean isShown) + { + featureType = type; + featureColour = colour; + filter = theFilter; + show = isShown; + } + } /* * global transparency for feature @@ -68,7 +91,7 @@ public abstract class FeatureRendererModel /* * filters for each feature type */ - protected Map featureFilters = new HashMap<>(); + protected Map featureFilters = new HashMap<>(); protected String[] renderOrder; @@ -169,7 +192,7 @@ public abstract class FeatureRendererModel { av.setFeaturesDisplayed(fdi = new FeaturesDisplayed()); } - List nft = new ArrayList(); + List nft = new ArrayList<>(); for (String featureType : featureTypes) { if (!fdi.isRegistered(featureType)) @@ -205,7 +228,7 @@ public abstract class FeatureRendererModel renderOrder = neworder; } - protected Map minmax = new Hashtable(); + protected Map minmax = new Hashtable<>(); public Map getMinMax() { @@ -243,11 +266,14 @@ public abstract class FeatureRendererModel boolean findingFeatures = false; + int nup; + protected boolean updateFeatures() { if (av.getFeaturesDisplayed() == null || renderOrder == null || newFeatureAdded) { + System.out.println("updateFeatures " + ++nup); findAllFeatures(); if (av.getFeaturesDisplayed().getVisibleFeatureCount() < 1) { @@ -284,7 +310,7 @@ public abstract class FeatureRendererModel * include features at the position provided their feature type is * displayed, and feature group is null or marked for display */ - List result = new ArrayList(); + List result = new ArrayList<>(); if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null) { return result; @@ -297,9 +323,13 @@ public abstract class FeatureRendererModel List features = sequence.findFeatures(column, column, visibleTypes); + /* + * include features unless their feature group is not displayed, or + * they are hidden (have no colour) based on a filter or colour threshold + */ for (SequenceFeature sf : features) { - if (!featureGroupNotShown(sf)) + if (!featureGroupNotShown(sf) && getColour(sf) != null) { result.add(sf); } @@ -333,7 +363,7 @@ public abstract class FeatureRendererModel } FeaturesDisplayedI featuresDisplayed = av.getFeaturesDisplayed(); - Set oldfeatures = new HashSet(); + Set oldfeatures = new HashSet<>(); if (renderOrder != null) { for (int i = 0; i < renderOrder.length; i++) @@ -346,7 +376,7 @@ public abstract class FeatureRendererModel } AlignmentI alignment = av.getAlignment(); - List allfeatures = new ArrayList(); + List allfeatures = new ArrayList<>(); for (int i = 0; i < alignment.getHeight(); i++) { @@ -426,7 +456,7 @@ public abstract class FeatureRendererModel */ if (minmax == null) { - minmax = new Hashtable(); + minmax = new Hashtable<>(); } synchronized (minmax) { @@ -463,7 +493,7 @@ public abstract class FeatureRendererModel */ private void updateRenderOrder(List allFeatures) { - List allfeatures = new ArrayList(allFeatures); + List allfeatures = new ArrayList<>(allFeatures); String[] oldRender = renderOrder; renderOrder = new String[allfeatures.size()]; boolean initOrders = (featureOrder == null); @@ -586,7 +616,7 @@ public abstract class FeatureRendererModel * @param type * @return */ - protected boolean showFeatureOfType(String type) + public boolean showFeatureOfType(String type) { return type == null ? false : (av.getFeaturesDisplayed() == null ? true : av.getFeaturesDisplayed().isVisible(type)); @@ -624,7 +654,7 @@ public abstract class FeatureRendererModel { if (featureOrder == null) { - featureOrder = new Hashtable(); + featureOrder = new Hashtable<>(); } featureOrder.put(type, new Float(position)); return position; @@ -658,32 +688,33 @@ public abstract class FeatureRendererModel * Replace current ordering with new ordering * * @param data - * { String(Type), Colour(Type), Boolean(Displayed) } + * an array of { Type, Colour, Filter, Boolean } * @return true if any visible features have been reordered, else false */ - public boolean setFeaturePriority(Object[][] data) + public boolean setFeaturePriority(FeatureSettingsBean[] data) { return setFeaturePriority(data, true); } /** - * Sets the priority order for features, with the highest priority (displayed - * on top) at the start of the data array + * Sets the priority order for features, with the highest priority (displayed on + * top) at the start of the data array * * @param data - * { String(Type), Colour(Type), Boolean(Displayed) } + * an array of { Type, Colour, Filter, Boolean } * @param visibleNew * when true current featureDisplay list will be cleared - * @return true if any visible features have been reordered or recoloured, - * else false (i.e. no need to repaint) + * @return true if any visible features have been reordered or recoloured, else + * false (i.e. no need to repaint) */ - public boolean setFeaturePriority(Object[][] data, boolean visibleNew) + public boolean setFeaturePriority(FeatureSettingsBean[] data, + boolean visibleNew) { /* * note visible feature ordering and colours before update */ List visibleFeatures = getDisplayedFeatureTypes(); - Map visibleColours = new HashMap( + Map visibleColours = new HashMap<>( getFeatureColours()); FeaturesDisplayedI av_featuresdisplayed = null; @@ -716,9 +747,9 @@ public abstract class FeatureRendererModel { for (int i = 0; i < data.length; i++) { - String type = data[i][0].toString(); - setColour(type, (FeatureColourI) data[i][1]); - if (((Boolean) data[i][2]).booleanValue()) + String type = data[i].featureType; + setColour(type, data[i].featureColour); + if (data[i].show) { av_featuresdisplayed.setVisible(type); } @@ -843,7 +874,7 @@ public abstract class FeatureRendererModel { if (featureGroups != null) { - List gp = new ArrayList(); + List gp = new ArrayList<>(); for (String grp : featureGroups.keySet()) { @@ -889,7 +920,7 @@ public abstract class FeatureRendererModel @Override public Map getDisplayedFeatureCols() { - Map fcols = new Hashtable(); + Map fcols = new Hashtable<>(); if (getViewport().getFeaturesDisplayed() == null) { return fcols; @@ -917,7 +948,7 @@ public abstract class FeatureRendererModel public List getDisplayedFeatureTypes() { List typ = getRenderOrder(); - List displayed = new ArrayList(); + List displayed = new ArrayList<>(); FeaturesDisplayedI feature_disp = av.getFeaturesDisplayed(); if (feature_disp != null) { @@ -938,7 +969,7 @@ public abstract class FeatureRendererModel @Override public List getDisplayedFeatureGroups() { - List _gps = new ArrayList(); + List _gps = new ArrayList<>(); for (String gp : getFeatureGroups()) { if (checkGroupVisibility(gp, false)) @@ -973,7 +1004,7 @@ public abstract class FeatureRendererModel public List findFeaturesAtResidue(SequenceI sequence, int resNo) { - List result = new ArrayList(); + List result = new ArrayList<>(); if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null) { return result; @@ -993,7 +1024,7 @@ public abstract class FeatureRendererModel for (SequenceFeature sf : features) { - if (!featureGroupNotShown(sf)) + if (!featureGroupNotShown(sf) && getColour(sf) != null) { result.add(sf); } @@ -1002,19 +1033,27 @@ public abstract class FeatureRendererModel } /** - * Removes from the list of features any that duplicate the location of a - * feature of the same type. Should be used only for features of the same, - * simple, feature colour (which normally implies the same feature type). Does - * not check visibility settings for feature type or feature group. + * Removes from the list of features any whose group is not shown, or that are + * visible and duplicate the location of a visible feature of the same type. + * Should be used only for features of the same, simple, feature colour (which + * normally implies the same feature type). No filtering is done if + * transparency, or any feature filters, are in force. * * @param features */ public void filterFeaturesForDisplay(List features) { - if (features.isEmpty()) + /* + * don't remove 'redundant' features if + * - transparency is applied (feature count affects depth of feature colour) + * - filters are applied (not all features may be displayable) + */ + if (features.isEmpty() || transparency != 1f + || !featureFilters.isEmpty()) { return; } + SequenceFeatures.sortFeatures(features, true); SequenceFeature lastFeature = null; @@ -1022,6 +1061,11 @@ public abstract class FeatureRendererModel while (it.hasNext()) { SequenceFeature sf = it.next(); + if (featureGroupNotShown(sf)) + { + it.remove(); + continue; + } /* * a feature is redundant for rendering purposes if it has the @@ -1029,7 +1073,8 @@ public abstract class FeatureRendererModel * (checking type and isContactFeature as a fail-safe here, although * currently they are guaranteed to match in this context) */ - if (lastFeature != null && sf.getBegin() == lastFeature.getBegin() + if (lastFeature != null + && sf.getBegin() == lastFeature.getBegin() && sf.getEnd() == lastFeature.getEnd() && sf.isContactFeature() == lastFeature.isContactFeature() && sf.getType().equals(lastFeature.getType())) @@ -1041,25 +1086,25 @@ public abstract class FeatureRendererModel } @Override - public Map getFeatureFilters() + public Map getFeatureFilters() { - return new HashMap<>(featureFilters); + return featureFilters; } @Override - public void setFeatureFilters(Map filters) + public void setFeatureFilters(Map filters) { featureFilters = filters; } @Override - public KeyedMatcherSetI getFeatureFilter(String featureType) + public FeatureMatcherSetI getFeatureFilter(String featureType) { return featureFilters.get(featureType); } @Override - public void setFeatureFilter(String featureType, KeyedMatcherSetI filter) + public void setFeatureFilter(String featureType, FeatureMatcherSetI filter) { if (filter == null || filter.isEmpty()) { @@ -1073,8 +1118,8 @@ public abstract class FeatureRendererModel /** * Answers the colour for the feature, or null if the feature is excluded by - * feature type or group visibility, by filters, or by colour threshold - * settings + * feature group visibility, by filters, or by colour threshold settings. This + * method does not take feature visibility into account. * * @param sf * @param fc @@ -1083,14 +1128,6 @@ public abstract class FeatureRendererModel public Color getColor(SequenceFeature sf, FeatureColourI fc) { /* - * is the feature type displayed? - */ - if (!showFeatureOfType(sf.getType())) - { - return null; - } - - /* * is the feature group displayed? */ if (featureGroupNotShown(sf)) @@ -1119,9 +1156,62 @@ public abstract class FeatureRendererModel */ protected boolean featureMatchesFilters(SequenceFeature sf) { - KeyedMatcherSetI filter = featureFilters.get(sf.getType()); - return filter == null ? true : filter.matches(key -> sf - .getValueAsString(key)); + FeatureMatcherSetI filter = featureFilters.get(sf.getType()); + return filter == null ? true : filter.matches(sf); + } + + /** + * Answers true unless the specified group is set to hidden. Defaults to true + * if group visibility is not set. + * + * @param group + * @return + */ + public boolean isGroupVisible(String group) + { + if (!featureGroups.containsKey(group)) + { + return true; + } + return featureGroups.get(group); } + /** + * Orders features in render precedence (last in order is last to render, so + * displayed on top of other features) + * + * @param order + */ + public void orderFeatures(Comparator order) + { + Arrays.sort(renderOrder, order); + } + + @Override + public boolean isVisible(SequenceFeature feature) + { + if (feature == null) + { + return false; + } + if (getFeaturesDisplayed() == null + || !getFeaturesDisplayed().isVisible(feature.getType())) + { + return false; + } + if (featureGroupNotShown(feature)) + { + return false; + } + FeatureColourI fc = featureColours.get(feature.getType()); + if (fc != null && fc.isOutwithThreshold(feature)) + { + return false; + } + if (!featureMatchesFilters(feature)) + { + return false; + } + return true; + } }