X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FSequenceAnnotationReport.java;h=c3b076cb20ffe774079f5e8b24e154d75b88bbea;hb=136c0793b90b72b928c4d77dc109dd5c644e00d3;hp=89f1068e91691599078d0ccf77bf68592d61d3f6;hpb=9fc1c4d049a16cccb933e80b5be07ec36e6bda7f;p=jalview.git diff --git a/src/jalview/io/SequenceAnnotationReport.java b/src/jalview/io/SequenceAnnotationReport.java index 89f1068..c3b076c 100644 --- a/src/jalview/io/SequenceAnnotationReport.java +++ b/src/jalview/io/SequenceAnnotationReport.java @@ -21,13 +21,16 @@ package jalview.io; import jalview.datamodel.DBRefEntry; +import jalview.datamodel.DBRefSource; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.io.gff.GffConstants; +import jalview.util.MessageManager; import jalview.util.UrlLink; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -39,8 +42,70 @@ import java.util.Map; */ public class SequenceAnnotationReport { + private static final String COMMA = ","; + + private static final String ELLIPSIS = "..."; + + private static final int MAX_REFS_PER_SOURCE = 4; + + private static final int MAX_SOURCES = 40; + + private static final String[][] PRIMARY_SOURCES = new String[][] { + DBRefSource.CODINGDBS, DBRefSource.DNACODINGDBS, + DBRefSource.PROTEINDBS }; + final String linkImageURL; + /* + * Comparator to order DBRefEntry by Source + accession id (case-insensitive), + * with 'Primary' sources placed before others + */ + private static Comparator comparator = new Comparator() + { + + @Override + public int compare(DBRefEntry ref1, DBRefEntry ref2) + { + String s1 = ref1.getSource(); + String s2 = ref2.getSource(); + boolean s1Primary = isPrimarySource(s1); + boolean s2Primary = isPrimarySource(s2); + if (s1Primary && !s2Primary) + { + return -1; + } + if (!s1Primary && s2Primary) + { + return 1; + } + int comp = s1 == null ? -1 : (s2 == null ? 1 : s1 + .compareToIgnoreCase(s2)); + if (comp == 0) + { + String a1 = ref1.getAccessionId(); + String a2 = ref2.getAccessionId(); + comp = a1 == null ? -1 : (a2 == null ? 1 : a1 + .compareToIgnoreCase(a2)); + } + return comp; + } + + private boolean isPrimarySource(String source) + { + for (String[] primary : PRIMARY_SOURCES) + { + for (String s : primary) + { + if (source.equals(s)) + { + return true; + } + } + } + return false; + } + }; + public SequenceAnnotationReport(String linkImageURL) { this.linkImageURL = linkImageURL; @@ -49,37 +114,35 @@ public class SequenceAnnotationReport /** * Append text for the list of features to the tooltip * - * @param tooltipText2 + * @param sb * @param rpos * @param features * @param minmax */ - public void appendFeatures(final StringBuffer tooltipText2, int rpos, + public void appendFeatures(final StringBuilder sb, int rpos, List features, Map minmax) { if (features != null) { for (SequenceFeature feature : features) { - appendFeature(tooltipText2, rpos, minmax, feature); + appendFeature(sb, rpos, minmax, feature); } } } /** - * Appends text for one sequence feature to the string buffer + * Appends the feature at rpos to the given buffer * * @param sb * @param rpos * @param minmax - * {{min, max}, {min, max}} positional and non-positional feature - * scores for this type * @param feature */ - void appendFeature(final StringBuffer sb, int rpos, + void appendFeature(final StringBuilder sb, int rpos, Map minmax, SequenceFeature feature) { - if ("disulfide bond".equals(feature.getType())) + if (feature.isContactFeature()) { if (feature.getBegin() == rpos || feature.getEnd() == rpos) { @@ -87,7 +150,8 @@ public class SequenceAnnotationReport { sb.append("
"); } - sb.append("disulfide bond ").append(feature.getBegin()).append(":") + sb.append(feature.getType()).append(" ").append(feature.getBegin()) + .append(":") .append(feature.getEnd()); } } @@ -109,7 +173,7 @@ public class SequenceAnnotationReport } if (feature.begin != feature.end) { - sb.append(" " + feature.end); + sb.append(" ").append(feature.end); } if (feature.getDescription() != null @@ -117,13 +181,12 @@ public class SequenceAnnotationReport { String tmpString = feature.getDescription(); String tmp2up = tmpString.toUpperCase(); - final int startTag = tmp2up.indexOf(""); + int startTag = tmp2up.indexOf(""); if (startTag > -1) { tmpString = tmpString.substring(startTag + 6); tmp2up = tmp2up.substring(startTag + 6); } - // TODO strips off but not - is that intended? int endTag = tmp2up.indexOf(""); if (endTag > -1) { @@ -148,7 +211,9 @@ public class SequenceAnnotationReport // be used, so we must remove < > symbols tmpString = tmpString.replaceAll("<", "<"); tmpString = tmpString.replaceAll(">", ">"); - sb.append("; ").append(tmpString); + + sb.append("; "); + sb.append(tmpString); } else { @@ -156,11 +221,7 @@ public class SequenceAnnotationReport } } } - - /* - * score should be shown if there is one, and min != max - * for this feature type (e.g. not all 0) - */ + // check score should be shown if (!Float.isNaN(feature.getScore())) { float[][] rng = (minmax == null) ? null : minmax.get(feature @@ -183,7 +244,6 @@ public class SequenceAnnotationReport } } } - appendLinks(sb, feature); } /** @@ -254,26 +314,42 @@ public class SequenceAnnotationReport return urlSets.values(); } - public void createSequenceAnnotationReport(final StringBuffer tip, + public void createSequenceAnnotationReport(final StringBuilder tip, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, Map minmax) { createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats, - true, minmax); + minmax, false); } - public void createSequenceAnnotationReport(final StringBuffer tip, + /** + * Builds an html formatted report of sequence details and appends it to the + * provided buffer. + * + * @param sb + * buffer to append report to + * @param sequence + * the sequence the report is for + * @param showDbRefs + * whether to include database references for the sequence + * @param showNpFeats + * whether to include non-positional sequence features + * @param minmax + * @param summary + * @return + */ + int createSequenceAnnotationReport(final StringBuilder sb, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, - boolean tableWrap, Map minmax) + Map minmax, boolean summary) { String tmp; - tip.append(""); + sb.append(""); int maxWidth = 0; if (sequence.getDescription() != null) { tmp = sequence.getDescription(); - tip.append("
" + tmp); + sb.append("
").append(tmp); maxWidth = Math.max(maxWidth, tmp.length()); } SequenceI ds = sequence; @@ -281,41 +357,135 @@ public class SequenceAnnotationReport { ds = ds.getDatasetSequence(); } - DBRefEntry[] dbrefs = ds.getDBRefs(); - if (showDbRefs && dbrefs != null) + + if (showDbRefs) + { + maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary)); + } + + /* + * add non-positional features if wanted + */ + if (showNpFeats) { - for (int i = 0; i < dbrefs.length; i++) + for (SequenceFeature sf : sequence.getFeatures() + .getNonPositionalFeatures()) { - tip.append("
"); - tmp = dbrefs[i].getSource() + " " + dbrefs[i].getAccessionId(); - tip.append(tmp); - maxWidth = Math.max(maxWidth, tmp.length()); + int sz = -sb.length(); + appendFeature(sb, 0, minmax, sf); + sz += sb.length(); + maxWidth = Math.max(maxWidth, sz); } } + sb.append("
"); + return maxWidth; + } - // ADD NON POSITIONAL SEQUENCE INFO - SequenceFeature[] features = sequence.getSequenceFeatures(); - if (showNpFeats && features != null) + /** + * A helper method that appends any DBRefs, returning the maximum line length + * added + * + * @param sb + * @param ds + * @param summary + * @return + */ + protected int appendDbRefs(final StringBuilder sb, SequenceI ds, + boolean summary) + { + DBRefEntry[] dbrefs = ds.getDBRefs(); + if (dbrefs == null) { - for (int i = 0; i < features.length; i++) + return 0; + } + + // note this sorts the refs held on the sequence! + Arrays.sort(dbrefs, comparator); + boolean ellipsis = false; + String source = null; + String lastSource = null; + int countForSource = 0; + int sourceCount = 0; + boolean moreSources = false; + int maxLineLength = 0; + int lineLength = 0; + + for (DBRefEntry ref : dbrefs) + { + source = ref.getSource(); + if (source == null) + { + // shouldn't happen + continue; + } + boolean sourceChanged = !source.equals(lastSource); + if (sourceChanged) + { + lineLength = 0; + countForSource = 0; + sourceCount++; + } + if (sourceCount > MAX_SOURCES && summary) + { + ellipsis = true; + moreSources = true; + break; + } + lastSource = source; + countForSource++; + if (countForSource == 1 || !summary) { - if (features[i].begin == 0 && features[i].end == 0) + sb.append("
"); + } + if (countForSource <= MAX_REFS_PER_SOURCE || !summary) + { + String accessionId = ref.getAccessionId(); + lineLength += accessionId.length() + 1; + if (countForSource > 1 && summary) + { + sb.append(", ").append(accessionId); + lineLength++; + } + else { - int sz = -tip.length(); - List tfeat = new ArrayList(); - tfeat.add(features[i]); - appendFeatures(tip, 0, tfeat, minmax); - sz += tip.length(); - maxWidth = Math.max(maxWidth, sz); + sb.append(source).append(" ").append(accessionId); + lineLength += source.length(); } + maxLineLength = Math.max(maxLineLength, lineLength); + } + if (countForSource == MAX_REFS_PER_SOURCE && summary) + { + sb.append(COMMA).append(ELLIPSIS); + ellipsis = true; } } - - if (tableWrap && maxWidth > 60) + if (moreSources) + { + sb.append("
").append(source) + .append(COMMA).append(ELLIPSIS); + } + if (ellipsis) { - tip.insert(0, "
"); - tip.append("
"); + sb.append("
("); + sb.append(MessageManager.getString("label.output_seq_details")); + sb.append(")"); } + return maxLineLength; + } + + public void createTooltipAnnotationReport(final StringBuilder tip, + SequenceI sequence, boolean showDbRefs, boolean showNpFeats, + Map minmax) + { + int maxWidth = createSequenceAnnotationReport(tip, sequence, + showDbRefs, showNpFeats, minmax, true); + + if (maxWidth > 60) + { + // ? not sure this serves any useful purpose + // tip.insert(0, "
"); + // tip.append("
"); + } } }