/* * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9.0b2) * Copyright (C) 2015 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.io.gff.GffConstants; import jalview.util.DBRefUtils; import jalview.util.UrlLink; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * generate HTML reports for a sequence * * @author jimp */ public class SequenceAnnotationReport { final String linkImageURL; public SequenceAnnotationReport(String linkImageURL) { this.linkImageURL = linkImageURL; } /** * Append text for the list of features to the tooltip * * @param tooltipText2 * @param rpos * @param features * @param minmax */ public void appendFeatures(final StringBuffer tooltipText2, int rpos, List features, Map minmax) { if (features != null) { for (SequenceFeature feature : features) { appendFeature(tooltipText2, rpos, minmax, feature); } } } /** * Appends text for one sequence feature to the string 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, Map minmax, SequenceFeature feature) { if ("disulfide bond".equals(feature.getType())) { if (feature.getBegin() == rpos || feature.getEnd() == rpos) { if (sb.length() > 6) { sb.append("
"); } sb.append("disulfide bond ").append(feature.getBegin()).append(":") .append(feature.getEnd()); } } else { if (sb.length() > 6) { sb.append("
"); } // TODO: remove this hack to display link only features boolean linkOnly = feature.getValue("linkonly") != null; if (!linkOnly) { sb.append(feature.getType()).append(" "); if (rpos != 0) { // we are marking a positional feature sb.append(feature.begin); } if (feature.begin != feature.end) { sb.append(" " + feature.end); } if (feature.getDescription() != null && !feature.description.equals(feature.getType())) { String tmpString = feature.getDescription(); String tmp2up = tmpString.toUpperCase(); final 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) { tmpString = tmpString.substring(0, endTag); tmp2up = tmp2up.substring(0, endTag); } endTag = tmp2up.indexOf(""); if (endTag > -1) { tmpString = tmpString.substring(0, endTag); } if (startTag > -1) { sb.append("; ").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(">", ">"); sb.append("; ").append(tmpString); } else { sb.append("; ").append(tmpString); } } } /* * score should be shown if there is one, and min != max * for this feature type (e.g. not all 0) */ if (!Float.isNaN(feature.getScore())) { float[][] rng = (minmax == null) ? null : minmax.get(feature .getType()); if (rng != null && rng[0] != null && rng[0][0] != rng[0][1]) { sb.append(" Score=").append(String.valueOf(feature.getScore())); } } String status = (String) feature.getValue("status"); if (status != null && status.length() > 0) { sb.append("; (").append(status).append(")"); } String clinSig = (String) feature .getValue(GffConstants.CLINICAL_SIGNIFICANCE); if (clinSig != null) { sb.append("; ").append(clinSig); } } } appendLinks(sb, feature); } /** * Format and appends any hyperlinks for the sequence feature to the string * buffer * * @param sb * @param feature */ void appendLinks(final StringBuffer sb, SequenceFeature feature) { if (feature.links != null) { if (linkImageURL != null) { sb.append(" "); } else { for (String urlstring : feature.links) { try { for (String[] urllink : createLinksFrom(null, urlstring)) { sb.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 }} */ String[][] createLinksFrom(SequenceI seq, String link) { List urlSets = new ArrayList(); List uniques = new ArrayList(); UrlLink urlLink = new UrlLink(link); if (!urlLink.isValid()) { System.err.println(urlLink.getInvalidMessage()); return null; } if (seq != null && urlLink.isDynamic()) { urlSets.addAll(createDynamicLinks(seq, urlLink, uniques)); } else { String target = urlLink.getTarget(); String label = urlLink.getLabel(); String unq = label + "|" + urlLink.getUrl_prefix(); if (!uniques.contains(unq)) { uniques.add(unq); urlSets.add(new String[] { target, label, null, urlLink.getUrl_prefix() }); } } return urlSets.toArray(new String[][] {}); } /** * Formats and returns a list of dynamic href links * * @param seq * @param urlLink * @param uniques */ List createDynamicLinks(SequenceI seq, UrlLink urlLink, List uniques) { List result = new ArrayList(); final String target = urlLink.getTarget(); final String label = urlLink.getLabel(); // collect matching db-refs DBRefEntry[] dbr = 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 URL 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)) { result.add(new String[] { target, label, urls[u], urls[u + 1] }); uniques.add(unq); } } } } } if (id != null) { // create Bare ID link for this URL 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)) { result.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)) { result.add(new String[] { target, label, urls[u], urls[u + 1] }); uniques.add(unq); } } } } return result; } public void createSequenceAnnotationReport(final StringBuffer tip, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, Map minmax) { createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats, true, minmax); } public void createSequenceAnnotationReport(final StringBuffer tip, SequenceI sequence, boolean showDbRefs, boolean showNpFeats, boolean tableWrap, Map minmax) { String tmp; tip.append(""); int maxWidth = 0; if (sequence.getDescription() != null) { tmp = sequence.getDescription(); tip.append("
" + tmp); maxWidth = Math.max(maxWidth, tmp.length()); } SequenceI ds = sequence; while (ds.getDatasetSequence() != null) { ds = ds.getDatasetSequence(); } DBRefEntry[] dbrefs = ds.getDBRefs(); if (showDbRefs && dbrefs != null) { for (int i = 0; i < dbrefs.length; i++) { tip.append("
"); tmp = dbrefs[i].getSource() + " " + dbrefs[i].getAccessionId(); tip.append(tmp); maxWidth = Math.max(maxWidth, tmp.length()); } } // 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 = -tip.length(); List tfeat = new ArrayList(); tfeat.add(features[i]); appendFeatures(tip, 0, tfeat, minmax); sz += tip.length(); maxWidth = Math.max(maxWidth, sz); } } } if (tableWrap && maxWidth > 60) { tip.insert(0, "
"); tip.append("
"); } } }