X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fviewmodel%2Fseqfeatures%2FFeatureRendererModel.java;h=426ec1fcd43170c5f1cb3d6c62d48fada136ac28;hb=56e3fef5ed30e5a12c5ab5618622118ac863bb58;hp=7faf7ea3be7219e0b12b023ac8abcbbdf461c717;hpb=4ffae060863956975d45807b6776dc7a5cf337b8;p=jalview.git diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 7faf7ea..426ec1f 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -20,11 +20,26 @@ */ 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.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.AlignmentI; +import jalview.datamodel.MappedFeatures; import jalview.datamodel.Mapping; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; @@ -37,20 +52,6 @@ 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; - public abstract class FeatureRendererModel implements jalview.api.FeatureRenderer { @@ -657,7 +658,7 @@ public abstract class FeatureRendererModel { featureOrder = new Hashtable<>(); } - featureOrder.put(type, new Float(position)); + featureOrder.put(type, Float.valueOf(position)); return position; } @@ -857,7 +858,7 @@ public abstract class FeatureRendererModel } if (newGroupsVisible) { - featureGroups.put(group, new Boolean(true)); + featureGroups.put(group, Boolean.valueOf(true)); return true; } return false; @@ -893,7 +894,7 @@ public abstract class FeatureRendererModel @Override public void setGroupVisibility(String group, boolean visible) { - featureGroups.put(group, new Boolean(visible)); + featureGroups.put(group, Boolean.valueOf(visible)); } @Override @@ -905,7 +906,7 @@ public abstract class FeatureRendererModel for (String gst : toset) { Boolean st = featureGroups.get(gst); - featureGroups.put(gst, new Boolean(visible)); + featureGroups.put(gst, Boolean.valueOf(visible)); if (st != null) { rdrw = rdrw || (visible != st.booleanValue()); @@ -1033,11 +1034,11 @@ 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. No - * filtering is done if transparency, or any feature filters, are in force. + * 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 */ @@ -1061,6 +1062,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 @@ -1068,7 +1074,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())) @@ -1154,31 +1161,42 @@ public abstract class FeatureRendererModel return filter == null ? true : filter.matches(sf); } - /** - * Answers a (possibly empty) list of features in this alignment at a position - * (or range) which is mappable from the given sequence residue position in a - * mapped alignment. - * - * @param sequence - * @param pos - * @return - */ - public List findComplementFeaturesAtResidue(SequenceI sequence, int pos) + @Override + public MappedFeatures findComplementFeaturesAtResidue( + final SequenceI sequence, final int pos) { SequenceI ds = sequence.getDatasetSequence(); - List result = new ArrayList<>(); + if (ds == null) + { + ds = sequence; + } + final char residue = ds.getCharAt(pos - ds.getStart()); + + List found = new ArrayList<>(); List mappings = this.av.getAlignment() .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; + SequenceI mapFrom = null; + for (AlignedCodonFrame acf : mappings) { - Mapping mapping = acf.getMappingForSequence(sequence, true); - if (mapping == null || mapping.getMap().getFromRatio() == mapping - .getMap().getToRatio()) + mapping = acf.getMappingForSequence(sequence); + if (mapping == null || !mapping.getMap().isTripletMap()) { continue; // we are only looking for 3:1 or 1:3 mappings } @@ -1188,19 +1206,83 @@ public abstract class FeatureRendererModel { int fromRes = match.getStart(); int toRes = match.getEnd(); + mapFrom = match.getSequence(); List fs = findFeaturesAtResidue( - match.getSequence(), fromRes, toRes); + mapFrom, fromRes, toRes); for (SequenceFeature sf : fs) { - if (!result.contains(sf)) + if (!found.contains(sf)) { - result.add(sf); + found.add(sf); } } } + + /* + * just take the first mapped features we find + */ + if (!found.isEmpty()) + { + break; + } + } + if (found.isEmpty()) + { + return null; + } + + /* + * 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) + { + if (type.equals(sf.getType())) + { + result.add(sf); + added++; + } + if (added == toAdd) + { + break; + } + } } - return result; + return new MappedFeatures(mapping, mapFrom, pos, residue, result); + } + + @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; } }