/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.io; import jalview.datamodel.DBRefEntry; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.util.UrlLink; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Hashtable; import java.util.List; /** * generate HTML reports for a sequence * * @author jimp */ public class SequenceAnnotationReport { final String linkImageURL; /* * Comparator to order DBRefEntry by Source + accession id (case-insensitive) */ private static Comparator comparator = new Comparator() { @Override public int compare(DBRefEntry ref1, DBRefEntry ref2) { String s1 = ref1.getSource(); String s2 = ref2.getSource(); 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; } }; public SequenceAnnotationReport(String linkImageURL) { this.linkImageURL = linkImageURL; } /** * appends the features at rpos to the given stringbuffer ready for display in * a tooltip * * @param tooltipText * @param linkImageURL * @param rpos * @param features * @param minmax * TODO refactor to Jalview 'utilities' somehow. */ public void appendFeatures(final StringBuilder tooltipText, int rpos, List features, Hashtable minmax) { String tmpString; if (features != null) { for (SequenceFeature feature : features) { if (feature.getType().equals("disulfide bond")) { if (feature.getBegin() == rpos || feature.getEnd() == rpos) { if (tooltipText.length() > 6) { tooltipText.append("
"); } tooltipText.append("disulfide bond " + feature.getBegin() + ":" + feature.getEnd()); } } else { if (tooltipText.length() > 6) { tooltipText.append("
"); } // TODO: remove this hack to display link only features boolean linkOnly = feature.getValue("linkonly") != null; if (!linkOnly) { tooltipText.append(feature.getType() + " "); if (rpos != 0) { // we are marking a positional feature tooltipText.append(feature.begin); } if (feature.begin != feature.end) { tooltipText.append(" " + feature.end); } if (feature.getDescription() != null && !feature.description.equals(feature.getType())) { tmpString = feature.getDescription(); String tmp2up = tmpString.toUpperCase(); int startTag = tmp2up.indexOf(""); if (startTag > -1) { tmpString = tmpString.substring(startTag + 6); tmp2up = tmp2up.substring(startTag + 6); } int endTag = tmp2up.indexOf(""); if (endTag > -1) { tmpString = tmpString.substring(0, endTag); tmp2up = tmp2up.substring(0, endTag); } endTag = tmp2up.indexOf(""); if (endTag > -1) { tmpString = tmpString.substring(0, endTag); } if (startTag > -1) { tooltipText.append("; " + tmpString); } else { if (tmpString.indexOf("<") > -1 || tmpString.indexOf(">") > -1) { // The description does not specify html is to // be used, so we must remove < > symbols tmpString = tmpString.replaceAll("<", "<"); tmpString = tmpString.replaceAll(">", ">"); tooltipText.append("; "); tooltipText.append(tmpString); } else { tooltipText.append("; " + tmpString); } } } // check score should be shown if (!Float.isNaN(feature.getScore())) { float[][] rng = (minmax == null) ? null : ((float[][]) minmax .get(feature.getType())); if (rng != null && rng[0] != null && rng[0][0] != rng[0][1]) { tooltipText.append(" Score=" + feature.getScore()); } } if (feature.getValue("status") != null) { String status = feature.getValue("status").toString(); if (status.length() > 0) { tooltipText.append("; (" + feature.getValue("status") + ")"); } } } } if (feature.links != null) { if (linkImageURL != null) { tooltipText.append(" "); } else { for (String urlstring : feature.links) { try { for (String[] urllink : createLinksFrom(null, urlstring)) { tooltipText.append("
" + (urllink[0].toLowerCase().equals( urllink[1].toLowerCase()) ? urllink[0] : (urllink[0] + ":" + urllink[1])) + "
"); } } catch (Exception x) { System.err.println("problem when creating links from " + urlstring); x.printStackTrace(); } } } } } } } /** * * @param seq * @param link * @return String[][] { String[] { link target, link label, dynamic component * inserted (if any), url }} */ public String[][] createLinksFrom(SequenceI seq, String link) { ArrayList urlSets = new ArrayList(); ArrayList uniques = new ArrayList(); UrlLink urlLink = new UrlLink(link); if (!urlLink.isValid()) { System.err.println(urlLink.getInvalidMessage()); return null; } final String target = urlLink.getTarget(); // link.substring(0, // link.indexOf("|")); final String label = urlLink.getLabel(); if (seq != null && urlLink.isDynamic()) { // collect matching db-refs DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs(seq.getDBRefs(), new String[] { target }); // collect id string too String id = seq.getName(); String descr = seq.getDescription(); if (descr != null && descr.length() < 1) { descr = null; } if (dbr != null) { for (int r = 0; r < dbr.length; r++) { if (id != null && dbr[r].getAccessionId().equals(id)) { // suppress duplicate link creation for the bare sequence ID // string with this link id = null; } // create Bare ID link for this RUL String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true); if (urls != null) { for (int u = 0; u < urls.length; u += 2) { String unq = urls[u] + "|" + urls[u + 1]; if (!uniques.contains(unq)) { urlSets.add(new String[] { target, label, urls[u], urls[u + 1] }); uniques.add(unq); } } } } } if (id != null) { // create Bare ID link for this RUL String[] urls = urlLink.makeUrls(id, true); if (urls != null) { for (int u = 0; u < urls.length; u += 2) { String unq = urls[u] + "|" + urls[u + 1]; if (!uniques.contains(unq)) { urlSets.add(new String[] { target, label, urls[u], urls[u + 1] }); uniques.add(unq); } } } } if (descr != null && urlLink.getRegexReplace() != null) { // create link for this URL from description only if regex matches String[] urls = urlLink.makeUrls(descr, true); if (urls != null) { for (int u = 0; u < urls.length; u += 2) { String unq = urls[u] + "|" + urls[u + 1]; if (!uniques.contains(unq)) { urlSets.add(new String[] { target, label, urls[u], urls[u + 1] }); uniques.add(unq); } } } } } else { String unq = label + "|" + urlLink.getUrl_prefix(); if (!uniques.contains(unq)) { uniques.add(unq); // Add a non-dynamic link urlSets.add(new String[] { target, label, null, urlLink.getUrl_prefix() }); } } return urlSets.toArray(new String[][] {}); } public void createTooltipAnnotationReport(final StringBuilder tip, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, Hashtable minmax) { int maxWidth = createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats, minmax, true); if (maxWidth > 60) { tip.insert(0, "
"); tip.append("
"); } } public int createSequenceAnnotationReport(final StringBuilder tip, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, Hashtable minmax) { return createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats, minmax, false); } /** * Adds an html-formatted sequence annotation report to the provided string * buffer, and returns the longest line length added * * @param sb * @param sequence * @param showDbRefs * if true, include database references * @param showNpFeats * if true, include non-positional sequence features * @param minmax * @param summary * if true, build a shortened summary report (for tooltip) * @return */ int createSequenceAnnotationReport(final StringBuilder sb, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, Hashtable minmax, boolean summary) { String tmp; sb.append(""); int maxWidth = 0; if (sequence.getDescription() != null) { tmp = sequence.getDescription(); sb.append("
").append(tmp); maxWidth = Math.max(maxWidth, tmp.length()); } SequenceI ds = sequence; while (ds.getDatasetSequence() != null) { ds = ds.getDatasetSequence(); } DBRefEntry[] dbrefs = ds.getDBRefs(); Arrays.sort(dbrefs, comparator); if (showDbRefs && dbrefs != null) { boolean ellipsis = false; String lastSource = null; int countForSource = 0; for (DBRefEntry ref : dbrefs) { String source = ref.getSource(); if (source == null) { // shouldn't happen continue; } boolean sourceChanged = !source.equals(lastSource); if (sourceChanged) { countForSource = 0; } lastSource = source; countForSource++; if (countForSource == 1 || !summary) { sb.append("
"); } if (countForSource < 3 || !summary) { String accessionId = ref.getAccessionId(); int len = accessionId.length() + 1; if (countForSource > 1 && summary) { sb.append(", ").append(accessionId); len++; } else { sb.append(source).append(" ").append(accessionId); len += source.length(); } maxWidth = Math.max(maxWidth, len); } if (countForSource == 3 && summary) { sb.append(", ..."); ellipsis = true; } } if (ellipsis) { sb.append("
(Output Sequence Details to list all database references)"); } } // ADD NON POSITIONAL SEQUENCE INFO SequenceFeature[] features = sequence.getSequenceFeatures(); if (showNpFeats && features != null) { for (int i = 0; i < features.length; i++) { if (features[i].begin == 0 && features[i].end == 0) { int sz = -sb.length(); List tfeat = Collections .singletonList(features[i]); appendFeatures(sb, 0, tfeat, minmax); sz += sb.length(); maxWidth = Math.max(maxWidth, sz); } } } return maxWidth; } }