2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.datamodel.DBRefEntry;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceI;
26 import jalview.util.UrlLink;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.Comparator;
32 import java.util.Hashtable;
33 import java.util.List;
36 * generate HTML reports for a sequence
40 public class SequenceAnnotationReport
42 final String linkImageURL;
45 * Comparator to order DBRefEntry by Source + accession id (case-insensitive)
47 private static Comparator<DBRefEntry> comparator = new Comparator<DBRefEntry>()
50 public int compare(DBRefEntry ref1, DBRefEntry ref2)
52 String s1 = ref1.getSource();
53 String s2 = ref2.getSource();
54 int comp = s1 == null ? -1 : (s2 == null ? 1 : s1
55 .compareToIgnoreCase(s2));
58 String a1 = ref1.getAccessionId();
59 String a2 = ref2.getAccessionId();
60 comp = a1 == null ? -1 : (a2 == null ? 1 : a1
61 .compareToIgnoreCase(a2));
67 public SequenceAnnotationReport(String linkImageURL)
69 this.linkImageURL = linkImageURL;
73 * appends the features at rpos to the given stringbuffer ready for display in
81 * TODO refactor to Jalview 'utilities' somehow.
83 public void appendFeatures(final StringBuilder tooltipText, int rpos,
84 List<SequenceFeature> features, Hashtable minmax)
89 for (SequenceFeature feature : features)
91 if (feature.getType().equals("disulfide bond"))
93 if (feature.getBegin() == rpos || feature.getEnd() == rpos)
95 if (tooltipText.length() > 6)
97 tooltipText.append("<br>");
99 tooltipText.append("disulfide bond " + feature.getBegin()
100 + ":" + feature.getEnd());
105 if (tooltipText.length() > 6)
107 tooltipText.append("<br>");
109 // TODO: remove this hack to display link only features
110 boolean linkOnly = feature.getValue("linkonly") != null;
113 tooltipText.append(feature.getType() + " ");
116 // we are marking a positional feature
117 tooltipText.append(feature.begin);
119 if (feature.begin != feature.end)
121 tooltipText.append(" " + feature.end);
124 if (feature.getDescription() != null
125 && !feature.description.equals(feature.getType()))
127 tmpString = feature.getDescription();
128 String tmp2up = tmpString.toUpperCase();
129 int startTag = tmp2up.indexOf("<HTML>");
132 tmpString = tmpString.substring(startTag + 6);
133 tmp2up = tmp2up.substring(startTag + 6);
135 int endTag = tmp2up.indexOf("</BODY>");
138 tmpString = tmpString.substring(0, endTag);
139 tmp2up = tmp2up.substring(0, endTag);
141 endTag = tmp2up.indexOf("</HTML>");
144 tmpString = tmpString.substring(0, endTag);
149 tooltipText.append("; " + tmpString);
153 if (tmpString.indexOf("<") > -1
154 || tmpString.indexOf(">") > -1)
156 // The description does not specify html is to
157 // be used, so we must remove < > symbols
158 tmpString = tmpString.replaceAll("<", "<");
159 tmpString = tmpString.replaceAll(">", ">");
161 tooltipText.append("; ");
162 tooltipText.append(tmpString);
167 tooltipText.append("; " + tmpString);
171 // check score should be shown
172 if (!Float.isNaN(feature.getScore()))
174 float[][] rng = (minmax == null) ? null : ((float[][]) minmax
175 .get(feature.getType()));
176 if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
178 tooltipText.append(" Score=" + feature.getScore());
181 if (feature.getValue("status") != null)
183 String status = feature.getValue("status").toString();
184 if (status.length() > 0)
186 tooltipText.append("; (" + feature.getValue("status")
192 if (feature.links != null)
194 if (linkImageURL != null)
196 tooltipText.append(" <img src=\"" + linkImageURL + "\">");
200 for (String urlstring : feature.links)
204 for (String[] urllink : createLinksFrom(null, urlstring))
206 tooltipText.append("<br/> <a href=\""
211 + (urllink[0].toLowerCase().equals(
212 urllink[1].toLowerCase()) ? urllink[0]
213 : (urllink[0] + ":" + urllink[1]))
216 } catch (Exception x)
218 System.err.println("problem when creating links from "
234 * @return String[][] { String[] { link target, link label, dynamic component
235 * inserted (if any), url }}
237 public String[][] createLinksFrom(SequenceI seq, String link)
239 ArrayList<String[]> urlSets = new ArrayList<String[]>();
240 ArrayList<String> uniques = new ArrayList<String>();
241 UrlLink urlLink = new UrlLink(link);
242 if (!urlLink.isValid())
244 System.err.println(urlLink.getInvalidMessage());
247 final String target = urlLink.getTarget(); // link.substring(0,
248 // link.indexOf("|"));
249 final String label = urlLink.getLabel();
250 if (seq != null && urlLink.isDynamic())
253 // collect matching db-refs
254 DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs(seq.getDBRefs(),
255 new String[] { target });
256 // collect id string too
257 String id = seq.getName();
258 String descr = seq.getDescription();
259 if (descr != null && descr.length() < 1)
265 for (int r = 0; r < dbr.length; r++)
267 if (id != null && dbr[r].getAccessionId().equals(id))
269 // suppress duplicate link creation for the bare sequence ID
270 // string with this link
273 // create Bare ID link for this RUL
274 String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
277 for (int u = 0; u < urls.length; u += 2)
279 String unq = urls[u] + "|" + urls[u + 1];
280 if (!uniques.contains(unq))
282 urlSets.add(new String[] { target, label, urls[u],
292 // create Bare ID link for this RUL
293 String[] urls = urlLink.makeUrls(id, true);
296 for (int u = 0; u < urls.length; u += 2)
298 String unq = urls[u] + "|" + urls[u + 1];
299 if (!uniques.contains(unq))
301 urlSets.add(new String[] { target, label, urls[u],
308 if (descr != null && urlLink.getRegexReplace() != null)
310 // create link for this URL from description only if regex matches
311 String[] urls = urlLink.makeUrls(descr, true);
314 for (int u = 0; u < urls.length; u += 2)
316 String unq = urls[u] + "|" + urls[u + 1];
317 if (!uniques.contains(unq))
319 urlSets.add(new String[] { target, label, urls[u],
330 String unq = label + "|" + urlLink.getUrl_prefix();
331 if (!uniques.contains(unq))
334 // Add a non-dynamic link
335 urlSets.add(new String[] { target, label, null,
336 urlLink.getUrl_prefix() });
340 return urlSets.toArray(new String[][] {});
343 public void createTooltipAnnotationReport(final StringBuilder tip,
344 SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
347 int maxWidth = createSequenceAnnotationReport(tip, sequence,
348 showDbRefs, showNpFeats, minmax, true);
352 tip.insert(0, "<table width=350 border=0><tr><td><i>");
353 tip.append("</i></td></tr></table>");
357 public int createSequenceAnnotationReport(final StringBuilder tip,
358 SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
361 return createSequenceAnnotationReport(tip, sequence, showDbRefs,
362 showNpFeats, minmax, false);
366 * Adds an html-formatted sequence annotation report to the provided string
367 * buffer, and returns the longest line length added
372 * if true, include database references
374 * if true, include non-positional sequence features
377 * if true, build a shortened summary report (for tooltip)
380 int createSequenceAnnotationReport(final StringBuilder sb,
381 SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
382 Hashtable minmax, boolean summary)
388 if (sequence.getDescription() != null)
390 tmp = sequence.getDescription();
391 sb.append("<br>").append(tmp);
392 maxWidth = Math.max(maxWidth, tmp.length());
394 SequenceI ds = sequence;
395 while (ds.getDatasetSequence() != null)
397 ds = ds.getDatasetSequence();
399 DBRefEntry[] dbrefs = ds.getDBRefs();
400 Arrays.sort(dbrefs, comparator);
401 if (showDbRefs && dbrefs != null)
403 boolean ellipsis = false;
404 String lastSource = null;
405 int countForSource = 0;
406 for (DBRefEntry ref : dbrefs)
408 String source = ref.getSource();
414 boolean sourceChanged = !source.equals(lastSource);
421 if (countForSource == 1 || !summary)
425 if (countForSource < 3 || !summary)
427 String accessionId = ref.getAccessionId();
428 int len = accessionId.length() + 1;
429 if (countForSource > 1 && summary)
431 sb.append(", ").append(accessionId);
436 sb.append(source).append(" ").append(accessionId);
437 len += source.length();
439 maxWidth = Math.max(maxWidth, len);
441 if (countForSource == 3 && summary)
448 sb.append("<br>(Output Sequence Details to list all database references)");
452 // ADD NON POSITIONAL SEQUENCE INFO
453 SequenceFeature[] features = sequence.getSequenceFeatures();
454 if (showNpFeats && features != null)
456 for (int i = 0; i < features.length; i++)
458 if (features[i].begin == 0 && features[i].end == 0)
460 int sz = -sb.length();
461 List<SequenceFeature> tfeat = Collections
462 .singletonList(features[i]);
463 appendFeatures(sb, 0, tfeat, minmax);
465 maxWidth = Math.max(maxWidth, sz);