X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fviewmodel%2Fseqfeatures%2FFeatureRendererModel.java;h=e812ed58c594ad5c3e890ab872344351800f9869;hb=57738a1f3c19b1c3a00bd3ac5108f8cd0af32f99;hp=2a17bf203587aeaab09b46e5a8a22316aaebe7ce;hpb=74393b51f368cb9f58589472d432a433d9c4386d;p=jalview.git diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 2a17bf2..e812ed5 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -20,13 +20,28 @@ */ package jalview.viewmodel.seqfeatures; +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; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import jalview.api.AlignViewportI; import jalview.api.FeatureColourI; import jalview.api.FeaturesDisplayedI; import jalview.datamodel.AlignedCodonFrame; +import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; import jalview.datamodel.AlignmentI; import jalview.datamodel.MappedFeatures; -import jalview.datamodel.Mapping; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -37,20 +52,7 @@ import jalview.datamodel.features.SequenceFeatures; import jalview.renderer.seqfeatures.FeatureRenderer; import jalview.schemes.FeatureColour; import jalview.util.ColorUtils; - -import java.awt.Color; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import jalview.util.Platform; public abstract class FeatureRendererModel implements jalview.api.FeatureRenderer @@ -102,11 +104,11 @@ public abstract class FeatureRendererModel Map featureOrder = null; - protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); - protected AlignViewportI av; + private PropertyChangeSupport changeSupport = new PropertyChangeSupport( + this); + @Override public AlignViewportI getViewport() { @@ -299,14 +301,21 @@ public abstract class FeatureRendererModel { firing = Boolean.TRUE; findAllFeatures(true); // add all new features as visible - changeSupport.firePropertyChange("changeSupport", null, null); + notifyFeaturesChanged(); firing = Boolean.FALSE; } } } @Override - public List findFeaturesAtColumn(SequenceI sequence, int column) + public void notifyFeaturesChanged() + { + changeSupport.firePropertyChange("changeSupport", null, null); + } + + @Override + public List findFeaturesAtColumn(SequenceI sequence, + int column) { /* * include features at the position provided their feature type is @@ -400,8 +409,8 @@ public abstract class FeatureRendererModel } if (groupDisplayed) { - Set types = asq.getFeatures().getFeatureTypesForGroups( - true, group); + Set types = asq.getFeatures() + .getFeatureTypesForGroups(true, group); for (String type : types) { if (!allfeatures.contains(type)) // or use HashSet and no test? @@ -480,6 +489,7 @@ public abstract class FeatureRendererModel } } } + protected Boolean firing = Boolean.FALSE; /** @@ -618,10 +628,11 @@ 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)); + return type == null ? false + : (av.getFeaturesDisplayed() == null ? true + : av.getFeaturesDisplayed().isVisible(type)); } @Override @@ -699,15 +710,15 @@ public abstract class FeatureRendererModel } /** - * 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 * 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(FeatureSettingsBean[] data, boolean visibleNew) @@ -991,8 +1002,7 @@ public abstract class FeatureRendererModel */ public boolean featureGroupNotShown(final SequenceFeature sequenceFeature) { - return featureGroups != null - && sequenceFeature.featureGroup != null + return featureGroups != null && sequenceFeature.featureGroup != null && sequenceFeature.featureGroup.length() != 0 && featureGroups.containsKey(sequenceFeature.featureGroup) && !featureGroups.get(sequenceFeature.featureGroup) @@ -1020,9 +1030,9 @@ public abstract class FeatureRendererModel List visibleFeatures = getDisplayedFeatureTypes(); String[] visibleTypes = visibleFeatures .toArray(new String[visibleFeatures.size()]); - List features = sequence.getFeatures().findFeatures( - fromResNo, toResNo, visibleTypes); - + List features = sequence.getFeatures() + .findFeatures(fromResNo, toResNo, visibleTypes); + for (SequenceFeature sf : features) { if (!featureGroupNotShown(sf) && getColour(sf) != null) @@ -1045,6 +1055,14 @@ public abstract class FeatureRendererModel public void filterFeaturesForDisplay(List features) { /* + * fudge: JalviewJS's IntervalStore lacks the sort method called :-( + */ + if (Platform.isJS()) + { + return; + } + + /* * 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) @@ -1074,8 +1092,7 @@ 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())) @@ -1105,7 +1122,8 @@ public abstract class FeatureRendererModel } @Override - public void setFeatureFilter(String featureType, FeatureMatcherSetI filter) + public void setFeatureFilter(String featureType, + FeatureMatcherSetI filter) { if (filter == null || filter.isEmpty()) { @@ -1120,7 +1138,7 @@ public abstract class FeatureRendererModel /** * Answers the colour for the feature, or null if the feature is excluded by * feature group visibility, by filters, or by colour threshold settings. This - * method does not take feature visibility into account. + * method does not take feature type visibility into account. * * @param sf * @param fc @@ -1143,7 +1161,7 @@ public abstract class FeatureRendererModel { return null; } - + return fc.getColor(sf); } @@ -1162,18 +1180,35 @@ public abstract class FeatureRendererModel } /** - * Answers a bean containing a mapping, and a list of features in this - * alignment at a position (or range) which is mappable from the given - * sequence residue position in a mapped alignment. Features are returned in - * render order of feature type (on top last), with order within feature type - * undefined. If no features or mapping are found, answers null. + * Answers true unless the specified group is set to hidden. Defaults to true + * if group visibility is not set. * - * @param sequence - * @param pos + * @param group * @return */ - public MappedFeatures findComplementFeaturesAtResidue(SequenceI sequence, - int pos) + 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 MappedFeatures findComplementFeaturesAtResidue( + final SequenceI sequence, final int pos) { SequenceI ds = sequence.getDatasetSequence(); if (ds == null) @@ -1187,29 +1222,38 @@ public abstract class FeatureRendererModel .getCodonFrame(sequence); /* + * fudge: if no mapping found, check the complementary alignment + * todo: only store in one place? StructureSelectionManager? + */ + if (mappings.isEmpty()) + { + mappings = this.av.getCodingComplement().getAlignment() + .getCodonFrame(sequence); + } + + /* * todo: direct lookup of CDS for peptide and vice-versa; for now, * have to search through an unordered list of mappings for a candidate */ - Mapping mapping = null; + SequenceToSequenceMapping mapping = null; SequenceI mapFrom = null; for (AlignedCodonFrame acf : mappings) { - mapping = acf.getMappingForSequence(sequence, true); - if (mapping == null || mapping.getMap().getFromRatio() == mapping - .getMap().getToRatio()) + mapping = acf.getCoveringCodonMapping(ds); + if (mapping == null) { - continue; // we are only looking for 3:1 or 1:3 mappings + continue; } SearchResultsI sr = new SearchResults(); - acf.markMappedRegion(ds, pos, sr); + mapping.markMappedRegion(ds, pos, sr); for (SearchResultMatchI match : sr.getResults()) { int fromRes = match.getStart(); int toRes = match.getEnd(); mapFrom = match.getSequence(); - List fs = findFeaturesAtResidue( - match.getSequence(), fromRes, toRes); + List fs = findFeaturesAtResidue(mapFrom, fromRes, + toRes); for (SequenceFeature sf : fs) { if (!found.contains(sf)) @@ -1233,9 +1277,12 @@ public abstract class FeatureRendererModel } /* - * sort by renderorder, inefficiently + * sort by renderorder (inefficiently but ok for small scale); + * NB this sorts 'on top' feature to end, for rendering */ List result = new ArrayList<>(); + final int toAdd = found.size(); + int added = 0; for (String type : renderOrder) { for (SequenceFeature sf : found) @@ -1243,16 +1290,17 @@ public abstract class FeatureRendererModel if (type.equals(sf.getType())) { result.add(sf); - if (result.size() == found.size()) - { - return new MappedFeatures(mapping, mapFrom, pos, residue, - result); - } + added++; + } + if (added == toAdd) + { + break; } } } - - return new MappedFeatures(mapping, mapFrom, pos, residue, result); + + return new MappedFeatures(mapping.getMapping(), mapFrom, pos, residue, + result); } @Override @@ -1282,5 +1330,4 @@ public abstract class FeatureRendererModel } return true; } - }