Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
SequenceAnnotationReport | 48 | 195 | 91 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
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. | |
11 | * | |
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. | |
16 | * | |
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. | |
20 | */ | |
21 | package jalview.io; | |
22 | ||
23 | import java.util.ArrayList; | |
24 | import java.util.Collection; | |
25 | import java.util.Comparator; | |
26 | import java.util.LinkedHashMap; | |
27 | import java.util.List; | |
28 | import java.util.Locale; | |
29 | import java.util.Map; | |
30 | ||
31 | import jalview.api.FeatureColourI; | |
32 | import jalview.datamodel.DBRefEntry; | |
33 | import jalview.datamodel.DBRefSource; | |
34 | import jalview.datamodel.GeneLociI; | |
35 | import jalview.datamodel.MappedFeatures; | |
36 | import jalview.datamodel.SequenceFeature; | |
37 | import jalview.datamodel.SequenceI; | |
38 | import jalview.util.MessageManager; | |
39 | import jalview.util.StringUtils; | |
40 | import jalview.util.UrlLink; | |
41 | import jalview.viewmodel.seqfeatures.FeatureRendererModel; | |
42 | ||
43 | /** | |
44 | * generate HTML reports for a sequence | |
45 | * | |
46 | * @author jimp | |
47 | */ | |
48 | public class SequenceAnnotationReport | |
49 | { | |
50 | private static final int MAX_DESCRIPTION_LENGTH = 40; | |
51 | ||
52 | private static final String COMMA = ","; | |
53 | ||
54 | private static final String ELLIPSIS = "..."; | |
55 | ||
56 | private static final int MAX_REFS_PER_SOURCE = 4; | |
57 | ||
58 | private static final int MAX_SOURCES = 5; | |
59 | ||
60 | private static String linkImageURL; | |
61 | ||
62 | // public static final String[][] PRIMARY_SOURCES moved to DBRefSource.java | |
63 | ||
64 | /* | |
65 | * Comparator to order DBRefEntry by Source + accession id (case-insensitive), | |
66 | * with 'Primary' sources placed before others, and 'chromosome' first of all | |
67 | */ | |
68 | private static Comparator<DBRefEntry> comparator = new Comparator<DBRefEntry>() | |
69 | { | |
70 | ||
71 | 24 | @Override |
72 | public int compare(DBRefEntry ref1, DBRefEntry ref2) | |
73 | { | |
74 | 24 | if (ref1 instanceof GeneLociI) |
75 | { | |
76 | 0 | return -1; |
77 | } | |
78 | 24 | if (ref2 instanceof GeneLociI) |
79 | { | |
80 | 0 | return 1; |
81 | } | |
82 | ||
83 | 24 | String s1 = ref1.getSource(); |
84 | 24 | String s2 = ref2.getSource(); |
85 | 24 | boolean s1Primary = DBRefSource.isPrimarySource(s1); |
86 | 24 | boolean s2Primary = DBRefSource.isPrimarySource(s2); |
87 | 24 | if (ref1.isCanonical() && !ref2.isCanonical()) |
88 | { | |
89 | 0 | return -1; |
90 | } | |
91 | 24 | if (!ref1.isCanonical() && ref2.isCanonical()) |
92 | { | |
93 | 0 | return 1; |
94 | } | |
95 | 24 | if (s1Primary && !s2Primary) |
96 | { | |
97 | 14 | return -1; |
98 | } | |
99 | 10 | if (!s1Primary && s2Primary) |
100 | { | |
101 | 0 | return 1; |
102 | } | |
103 | 10 | int comp = s1 == null ? -1 |
104 | 10 | : (s2 == null ? 1 : s1.compareToIgnoreCase(s2)); |
105 | 10 | if (comp == 0) |
106 | { | |
107 | 5 | String a1 = ref1.getAccessionId(); |
108 | 5 | String a2 = ref2.getAccessionId(); |
109 | 5 | comp = a1 == null ? -1 |
110 | 5 | : (a2 == null ? 1 : a1.compareToIgnoreCase(a2)); |
111 | } | |
112 | 10 | return comp; |
113 | } | |
114 | ||
115 | // private boolean isPrimarySource(String source) | |
116 | // { | |
117 | // for (String[] primary : DBRefSource.PRIMARY_SOURCES) | |
118 | // { | |
119 | // for (String s : primary) | |
120 | // { | |
121 | // if (source.equals(s)) | |
122 | // { | |
123 | // return true; | |
124 | // } | |
125 | // } | |
126 | // } | |
127 | // return false; | |
128 | // } | |
129 | }; | |
130 | ||
131 | private boolean forTooltip; | |
132 | ||
133 | /** | |
134 | * Constructor given a flag which affects behaviour | |
135 | * <ul> | |
136 | * <li>if true, generates feature details suitable to show in a tooltip</li> | |
137 | * <li>if false, generates feature details in a form suitable for the sequence | |
138 | * details report</li> | |
139 | * </ul> | |
140 | * | |
141 | * @param isForTooltip | |
142 | */ | |
143 | 968 | public SequenceAnnotationReport(boolean isForTooltip) |
144 | { | |
145 | 968 | this.forTooltip = isForTooltip; |
146 | 968 | if (linkImageURL == null) |
147 | { | |
148 | 50 | linkImageURL = getClass().getResource("/images/link.gif").toString(); |
149 | } | |
150 | } | |
151 | ||
152 | /** | |
153 | * Append text for the list of features to the tooltip. Returns the number of | |
154 | * features not added if maxlength limit is (or would have been) reached. | |
155 | * | |
156 | * @param sb | |
157 | * @param residuePos | |
158 | * @param features | |
159 | * @param minmax | |
160 | * @param maxlength | |
161 | */ | |
162 | 1 | public int appendFeatures(final StringBuilder sb, int residuePos, |
163 | List<SequenceFeature> features, FeatureRendererModel fr, | |
164 | int maxlength) | |
165 | { | |
166 | 4 | for (int i = 0; i < features.size(); i++) |
167 | { | |
168 | 4 | SequenceFeature feature = features.get(i); |
169 | 4 | if (appendFeature(sb, residuePos, fr, feature, null, maxlength)) |
170 | { | |
171 | 1 | return features.size() - i; |
172 | } | |
173 | } | |
174 | 0 | return 0; |
175 | } | |
176 | ||
177 | /** | |
178 | * Appends text for mapped features (e.g. CDS feature for peptide or vice | |
179 | * versa) Returns number of features left if maxlength limit is (or would have | |
180 | * been) reached. | |
181 | * | |
182 | * @param sb | |
183 | * @param residuePos | |
184 | * @param mf | |
185 | * @param fr | |
186 | * @param maxlength | |
187 | */ | |
188 | 0 | public int appendFeatures(StringBuilder sb, int residuePos, |
189 | MappedFeatures mf, FeatureRendererModel fr, int maxlength) | |
190 | { | |
191 | 0 | for (int i = 0; i < mf.features.size(); i++) |
192 | { | |
193 | 0 | SequenceFeature feature = mf.features.get(i); |
194 | 0 | if (appendFeature(sb, residuePos, fr, feature, mf, maxlength)) |
195 | { | |
196 | 0 | return mf.features.size() - i; |
197 | } | |
198 | } | |
199 | 0 | return 0; |
200 | } | |
201 | ||
202 | /** | |
203 | * Appends the feature at rpos to the given buffer | |
204 | * | |
205 | * @param sb | |
206 | * @param rpos | |
207 | * @param minmax | |
208 | * @param feature | |
209 | */ | |
210 | 41 | boolean appendFeature(final StringBuilder sb0, int rpos, |
211 | FeatureRendererModel fr, SequenceFeature feature, | |
212 | MappedFeatures mf, int maxlength) | |
213 | { | |
214 | 41 | int begin = feature.getBegin(); |
215 | 41 | int end = feature.getEnd(); |
216 | ||
217 | /* | |
218 | * if this is a virtual features, convert begin/end to the | |
219 | * coordinates of the sequence it is mapped to | |
220 | */ | |
221 | 41 | int[] beginRange = null; // feature start in local coordinates |
222 | 41 | int[] endRange = null; // feature end in local coordinates |
223 | 41 | if (mf != null) |
224 | { | |
225 | 3 | if (feature.isContactFeature()) |
226 | { | |
227 | /* | |
228 | * map start and end points individually | |
229 | */ | |
230 | 0 | beginRange = mf.getMappedPositions(begin, begin); |
231 | 0 | endRange = begin == end ? beginRange |
232 | : mf.getMappedPositions(end, end); | |
233 | } | |
234 | else | |
235 | { | |
236 | /* | |
237 | * map the feature extent | |
238 | */ | |
239 | 3 | beginRange = mf.getMappedPositions(begin, end); |
240 | 3 | endRange = beginRange; |
241 | } | |
242 | 3 | if (beginRange == null || endRange == null) |
243 | { | |
244 | // something went wrong | |
245 | 0 | return false; |
246 | } | |
247 | 3 | begin = beginRange[0]; |
248 | 3 | end = endRange[endRange.length - 1]; |
249 | } | |
250 | ||
251 | 41 | StringBuilder sb = new StringBuilder(); |
252 | 41 | if (feature.isContactFeature()) |
253 | { | |
254 | /* | |
255 | * include if rpos is at start or end position of [mapped] feature | |
256 | */ | |
257 | 3 | boolean showContact = (mf == null) && (rpos == begin || rpos == end); |
258 | 3 | boolean showMappedContact = (mf != null) && ((rpos >= beginRange[0] |
259 | && rpos <= beginRange[beginRange.length - 1]) | |
260 | || (rpos >= endRange[0] | |
261 | && rpos <= endRange[endRange.length - 1])); | |
262 | 3 | if (showContact || showMappedContact) |
263 | { | |
264 | 2 | if (sb0.length() > 6) |
265 | { | |
266 | 1 | sb.append("<br/>"); |
267 | } | |
268 | 2 | sb.append(feature.getType()).append(" ").append(begin).append(":") |
269 | .append(end); | |
270 | } | |
271 | 3 | return appendText(sb0, sb, maxlength); |
272 | } | |
273 | ||
274 | 38 | if (sb0.length() > 6) |
275 | { | |
276 | 21 | sb.append("<br/>"); |
277 | } | |
278 | // TODO: remove this hack to display link only features | |
279 | 38 | boolean linkOnly = feature.getValue("linkonly") != null; |
280 | 38 | if (!linkOnly) |
281 | { | |
282 | 38 | sb.append(feature.getType()).append(" "); |
283 | 38 | if (rpos != 0) |
284 | { | |
285 | // we are marking a positional feature | |
286 | 21 | sb.append(begin); |
287 | 21 | if (begin != end) |
288 | { | |
289 | 19 | sb.append(" ").append(end); |
290 | } | |
291 | } | |
292 | ||
293 | 38 | String description = feature.getDescription(); |
294 | 38 | if (description != null && !description.equals(feature.getType())) |
295 | { | |
296 | 37 | description = StringUtils.stripHtmlTags(description); |
297 | ||
298 | /* | |
299 | * truncate overlong descriptions unless they contain an href | |
300 | * before the truncation point (as truncation could leave corrupted html) | |
301 | */ | |
302 | 37 | int linkindex = description.toLowerCase(Locale.ROOT).indexOf("<a "); |
303 | 37 | boolean hasLink = linkindex > -1 |
304 | && linkindex < MAX_DESCRIPTION_LENGTH; | |
305 | 37 | if (description.length() > MAX_DESCRIPTION_LENGTH && !hasLink) |
306 | { | |
307 | 6 | description = description.substring(0, MAX_DESCRIPTION_LENGTH) |
308 | + ELLIPSIS; | |
309 | } | |
310 | ||
311 | 37 | sb.append("; ").append(description); |
312 | } | |
313 | ||
314 | 38 | if (showScore(feature, fr)) |
315 | { | |
316 | 5 | sb.append(" Score=").append(String.valueOf(feature.getScore())); |
317 | } | |
318 | 38 | String status = (String) feature.getValue("status"); |
319 | 38 | if (status != null && status.length() > 0) |
320 | { | |
321 | 2 | sb.append("; (").append(status).append(")"); |
322 | } | |
323 | ||
324 | /* | |
325 | * add attribute value if coloured by attribute | |
326 | */ | |
327 | 38 | if (fr != null) |
328 | { | |
329 | 27 | FeatureColourI fc = fr.getFeatureColours().get(feature.getType()); |
330 | 27 | if (fc != null && fc.isColourByAttribute()) |
331 | { | |
332 | 5 | String[] attName = fc.getAttributeName(); |
333 | 5 | String attVal = feature.getValueAsString(attName); |
334 | 5 | if (attVal != null) |
335 | { | |
336 | 4 | sb.append("; ").append(String.join(":", attName)).append("=") |
337 | .append(attVal); | |
338 | } | |
339 | } | |
340 | } | |
341 | ||
342 | 38 | if (mf != null) |
343 | { | |
344 | 3 | String variants = mf.findProteinVariants(feature); |
345 | 3 | if (!variants.isEmpty()) |
346 | { | |
347 | 1 | sb.append(" ").append(variants); |
348 | } | |
349 | } | |
350 | } | |
351 | 38 | return appendText(sb0, sb, maxlength); |
352 | } | |
353 | ||
354 | /** | |
355 | * Appends sb to sb0, and returns false, unless maxlength is not zero and | |
356 | * appending would make the result longer than or equal to maxlength, in which | |
357 | * case the append is not done and returns true | |
358 | * | |
359 | * @param sb0 | |
360 | * @param sb | |
361 | * @param maxlength | |
362 | * @return | |
363 | */ | |
364 | 41 | private static boolean appendText(StringBuilder sb0, StringBuilder sb, |
365 | int maxlength) | |
366 | { | |
367 | 41 | if (maxlength == 0 || sb0.length() + sb.length() < maxlength) |
368 | { | |
369 | 40 | sb0.append(sb); |
370 | 40 | return false; |
371 | } | |
372 | 1 | return true; |
373 | } | |
374 | ||
375 | /** | |
376 | * Answers true if score should be shown, else false. Score is shown if it is | |
377 | * not NaN, and the feature type has a non-trivial min-max score range | |
378 | */ | |
379 | 38 | boolean showScore(SequenceFeature feature, FeatureRendererModel fr) |
380 | { | |
381 | 38 | if (Float.isNaN(feature.getScore())) |
382 | { | |
383 | 11 | return false; |
384 | } | |
385 | 27 | if (fr == null) |
386 | { | |
387 | 3 | return true; |
388 | } | |
389 | 24 | float[][] minMax = fr.getMinMax().get(feature.getType()); |
390 | ||
391 | /* | |
392 | * minMax[0] is the [min, max] score range for positional features | |
393 | */ | |
394 | 24 | if (minMax == null || minMax[0] == null || minMax[0][0] == minMax[0][1]) |
395 | { | |
396 | 22 | return false; |
397 | } | |
398 | 2 | return true; |
399 | } | |
400 | ||
401 | /** | |
402 | * Format and appends any hyperlinks for the sequence feature to the string | |
403 | * buffer | |
404 | * | |
405 | * @param sb | |
406 | * @param feature | |
407 | */ | |
408 | 0 | void appendLinks(final StringBuffer sb, SequenceFeature feature) |
409 | { | |
410 | 0 | if (feature.links != null) |
411 | { | |
412 | 0 | if (linkImageURL != null) |
413 | { | |
414 | 0 | sb.append(" <img src=\"" + linkImageURL + "\">"); |
415 | } | |
416 | else | |
417 | { | |
418 | 0 | for (String urlstring : feature.links) |
419 | { | |
420 | 0 | try |
421 | { | |
422 | 0 | for (List<String> urllink : createLinksFrom(null, urlstring)) |
423 | { | |
424 | 0 | sb.append("<br/> <a href=\"" + urllink.get(3) + "\" target=\"" |
425 | + urllink.get(0) + "\">" | |
426 | 0 | + (urllink.get(0).toLowerCase(Locale.ROOT).equals( |
427 | urllink.get(1).toLowerCase(Locale.ROOT)) | |
428 | ? urllink.get(0) | |
429 | : (urllink.get(0) + ":" | |
430 | + urllink.get(1))) | |
431 | + "</a><br/>"); | |
432 | } | |
433 | } catch (Exception x) | |
434 | { | |
435 | 0 | jalview.bin.Console.errPrintln( |
436 | "problem when creating links from " + urlstring); | |
437 | 0 | x.printStackTrace(); |
438 | } | |
439 | } | |
440 | } | |
441 | ||
442 | } | |
443 | } | |
444 | ||
445 | /** | |
446 | * | |
447 | * @param seq | |
448 | * @param link | |
449 | * @return Collection< List<String> > { List<String> { link target, link | |
450 | * label, dynamic component inserted (if any), url }} | |
451 | */ | |
452 | 0 | Collection<List<String>> createLinksFrom(SequenceI seq, String link) |
453 | { | |
454 | 0 | Map<String, List<String>> urlSets = new LinkedHashMap<>(); |
455 | 0 | UrlLink urlLink = new UrlLink(link); |
456 | 0 | if (!urlLink.isValid()) |
457 | { | |
458 | 0 | jalview.bin.Console.errPrintln(urlLink.getInvalidMessage()); |
459 | 0 | return null; |
460 | } | |
461 | ||
462 | 0 | urlLink.createLinksFromSeq(seq, urlSets); |
463 | ||
464 | 0 | return urlSets.values(); |
465 | } | |
466 | ||
467 | 10 | public void createSequenceAnnotationReport(final StringBuilder tip, |
468 | SequenceI sequence, boolean showDbRefs, boolean showNpFeats, | |
469 | FeatureRendererModel fr) | |
470 | { | |
471 | 10 | createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats, |
472 | fr, false); | |
473 | } | |
474 | ||
475 | /** | |
476 | * Builds an html formatted report of sequence details and appends it to the | |
477 | * provided buffer. | |
478 | * | |
479 | * @param sb | |
480 | * buffer to append report to | |
481 | * @param sequence | |
482 | * the sequence the report is for | |
483 | * @param showDbRefs | |
484 | * whether to include database references for the sequence | |
485 | * @param showNpFeats | |
486 | * whether to include non-positional sequence features | |
487 | * @param fr | |
488 | * @param summary | |
489 | * @return | |
490 | */ | |
491 | 11 | int createSequenceAnnotationReport(final StringBuilder sb, |
492 | SequenceI sequence, boolean showDbRefs, boolean showNpFeats, | |
493 | FeatureRendererModel fr, boolean summary) | |
494 | { | |
495 | 11 | String tmp; |
496 | 11 | sb.append("<i>"); |
497 | ||
498 | 11 | int maxWidth = 0; |
499 | 11 | if (sequence.getDescription() != null) |
500 | { | |
501 | 10 | tmp = sequence.getDescription(); |
502 | 10 | sb.append(tmp); |
503 | 10 | maxWidth = Math.max(maxWidth, tmp.length()); |
504 | } | |
505 | 11 | sb.append("\n"); |
506 | 11 | SequenceI ds = sequence; |
507 | 11 | while (ds.getDatasetSequence() != null) |
508 | { | |
509 | 0 | ds = ds.getDatasetSequence(); |
510 | } | |
511 | ||
512 | 11 | if (showDbRefs) |
513 | { | |
514 | 9 | maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary)); |
515 | } | |
516 | 11 | sb.append("\n"); |
517 | ||
518 | /* | |
519 | * add non-positional features if wanted | |
520 | */ | |
521 | 11 | if (showNpFeats) |
522 | { | |
523 | 9 | for (SequenceFeature sf : sequence.getFeatures() |
524 | .getNonPositionalFeatures()) | |
525 | { | |
526 | 17 | int sz = -sb.length(); |
527 | 17 | appendFeature(sb, 0, fr, sf, null, 0); |
528 | 17 | sz += sb.length(); |
529 | 17 | maxWidth = Math.max(maxWidth, sz); |
530 | } | |
531 | } | |
532 | 11 | sb.append("</i>"); |
533 | 11 | return maxWidth; |
534 | } | |
535 | ||
536 | /** | |
537 | * A helper method that appends any DBRefs, returning the maximum line length | |
538 | * added | |
539 | * | |
540 | * @param sb | |
541 | * @param ds | |
542 | * @param summary | |
543 | * @return | |
544 | */ | |
545 | 9 | protected int appendDbRefs(final StringBuilder sb, SequenceI ds, |
546 | boolean summary) | |
547 | { | |
548 | 9 | List<DBRefEntry> dbrefs, dbrefset = ds.getDBRefs(); |
549 | ||
550 | 9 | if (dbrefset == null) |
551 | { | |
552 | 6 | return 0; |
553 | } | |
554 | ||
555 | // PATCH for JAL-3980 defensive copy | |
556 | ||
557 | 3 | dbrefs = new ArrayList<DBRefEntry>(); |
558 | ||
559 | 3 | dbrefs.addAll(dbrefset); |
560 | ||
561 | // note this sorts the refs held on the sequence! | |
562 | 3 | dbrefs.sort(comparator); |
563 | 3 | boolean ellipsis = false; |
564 | 3 | String source = null; |
565 | 3 | String lastSource = null; |
566 | 3 | int countForSource = 0; |
567 | 3 | int sourceCount = 0; |
568 | 3 | boolean moreSources = false; |
569 | 3 | int maxLineLength = 0; |
570 | 3 | int lineLength = 0; |
571 | ||
572 | 3 | for (DBRefEntry ref : dbrefs) |
573 | { | |
574 | 14 | source = ref.getSource(); |
575 | 14 | if (source == null) |
576 | { | |
577 | // shouldn't happen | |
578 | 0 | continue; |
579 | } | |
580 | 14 | boolean sourceChanged = !source.equals(lastSource); |
581 | 14 | if (sourceChanged) |
582 | { | |
583 | 10 | lineLength = 0; |
584 | 10 | countForSource = 0; |
585 | 10 | sourceCount++; |
586 | } | |
587 | 14 | if (sourceCount > MAX_SOURCES && summary) |
588 | { | |
589 | 1 | ellipsis = true; |
590 | 1 | moreSources = true; |
591 | 1 | break; |
592 | } | |
593 | 13 | lastSource = source; |
594 | 13 | countForSource++; |
595 | 13 | if (countForSource == 1 || !summary) |
596 | { | |
597 | 9 | sb.append("<br/>\n"); |
598 | } | |
599 | 13 | if (countForSource <= MAX_REFS_PER_SOURCE || !summary) |
600 | { | |
601 | 12 | String accessionId = ref.getAccessionId(); |
602 | 12 | lineLength += accessionId.length() + 1; |
603 | 12 | if (countForSource > 1 && summary) |
604 | { | |
605 | 3 | sb.append(",\n ").append(accessionId); |
606 | 3 | lineLength++; |
607 | } | |
608 | else | |
609 | { | |
610 | 9 | sb.append(source).append(" ").append(accessionId); |
611 | 9 | lineLength += source.length(); |
612 | } | |
613 | 12 | maxLineLength = Math.max(maxLineLength, lineLength); |
614 | } | |
615 | 13 | if (countForSource == MAX_REFS_PER_SOURCE && summary) |
616 | { | |
617 | 1 | sb.append(COMMA).append(ELLIPSIS); |
618 | 1 | ellipsis = true; |
619 | } | |
620 | } | |
621 | 3 | if (moreSources) |
622 | { | |
623 | 1 | sb.append("<br/>\n").append(source).append(COMMA).append(ELLIPSIS); |
624 | } | |
625 | 3 | if (ellipsis) |
626 | { | |
627 | 1 | sb.append("<br/>\n("); |
628 | 1 | sb.append(MessageManager.getString("label.output_seq_details")); |
629 | 1 | sb.append(")"); |
630 | } | |
631 | ||
632 | 3 | return maxLineLength; |
633 | } | |
634 | ||
635 | 0 | public void createTooltipAnnotationReport(final StringBuilder tip, |
636 | SequenceI sequence, boolean showDbRefs, boolean showNpFeats, | |
637 | FeatureRendererModel fr) | |
638 | { | |
639 | 0 | int maxWidth = createSequenceAnnotationReport(tip, sequence, showDbRefs, |
640 | showNpFeats, fr, true); | |
641 | ||
642 | 0 | if (maxWidth > 60) |
643 | { | |
644 | // ? not sure this serves any useful purpose | |
645 | // tip.insert(0, "<table width=350 border=0><tr><td>"); | |
646 | // tip.append("</td></tr></table>"); | |
647 | } | |
648 | } | |
649 | } |