Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 15:14:12 GMT
  2. Package jalview.gui

File SequenceRenderer.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
37% of files have more coverage

Code metrics

78
121
9
1
523
310
62
0.51
13.44
9
6.89

Classes

Class Line # Actions
SequenceRenderer 36 121 62
0.605769260.6%
 

Contributing tests

This file is covered by 189 tests. .

Source view

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.gui;
22   
23    import jalview.api.AlignViewportI;
24    import jalview.datamodel.SequenceGroup;
25    import jalview.datamodel.SequenceI;
26    import jalview.renderer.ResidueColourFinder;
27    import jalview.renderer.seqfeatures.FeatureColourFinder;
28   
29    import java.awt.Color;
30    import java.awt.FontMetrics;
31    import java.awt.Graphics;
32   
33    import org.jfree.graphics2d.svg.SVGGraphics2D;
34    import org.jibble.epsgraphics.EpsGraphics2D;
35   
 
36    public class SequenceRenderer implements jalview.api.SequenceRenderer
37    {
38    final static int CHAR_TO_UPPER = 'A' - 'a';
39   
40    AlignViewportI av;
41   
42    FontMetrics fm;
43   
44    boolean renderGaps = true;
45   
46    SequenceGroup[] allGroups = null;
47   
48    // Color resBoxColour;
49   
50    Graphics graphics;
51   
52    boolean monospacedFont;
53   
54    ResidueColourFinder resColourFinder;
55   
56    /**
57    * Creates a new SequenceRenderer object
58    *
59    * @param viewport
60    */
 
61  840 toggle public SequenceRenderer(AlignViewportI viewport)
62    {
63  840 this.av = viewport;
64  840 resColourFinder = new ResidueColourFinder();
65    }
66   
67    /**
68    * DOCUMENT ME!
69    *
70    * @param b
71    * DOCUMENT ME!
72    */
 
73  2877 toggle @Override
74    public void prepare(Graphics g, boolean renderGaps)
75    {
76  2877 graphics = g;
77  2877 fm = g.getFontMetrics();
78   
79    // If EPS graphics, stringWidth will be a double, not an int
80  2877 double dwidth = fm.getStringBounds("M", g).getWidth();
81   
82  2877 monospacedFont = (dwidth == fm.getStringBounds("|", g).getWidth()
83    && av.getCharWidth() == dwidth);
84   
85  2877 this.renderGaps = renderGaps;
86    }
87   
88    /**
89    * Get the residue colour at the given sequence position - as determined by
90    * the sequence group colour (if any), else the colour scheme, possibly
91    * overridden by a feature colour.
92    *
93    * @param seq
94    * @param position
95    * @param finder
96    * @return
97    */
 
98  32838 toggle @Override
99    public Color getResidueColour(final SequenceI seq, int position,
100    FeatureColourFinder finder)
101    {
102  32838 allGroups = av.getAlignment().findAllGroups(seq);
103  32839 return resColourFinder.getResidueColour(av.getShowBoxes(),
104    av.getResidueShading(), allGroups, seq, position, finder);
105    }
106   
107    /**
108    * DOCUMENT ME!
109    *
110    * @param g
111    * DOCUMENT ME!
112    * @param seq
113    * DOCUMENT ME!
114    * @param sg
115    * DOCUMENT ME!
116    * @param start
117    * DOCUMENT ME!
118    * @param end
119    * DOCUMENT ME!
120    * @param x1
121    * DOCUMENT ME!
122    * @param y1
123    * DOCUMENT ME!
124    * @param width
125    * DOCUMENT ME!
126    * @param height
127    * DOCUMENT ME!
128    */
 
129  14397 toggle public void drawSequence(SequenceI seq, SequenceGroup[] sg, int start,
130    int end, int y1)
131    {
132  14397 allGroups = sg;
133   
134  14397 drawBoxes(seq, start, end, y1);
135   
136  14397 if (av.isValidCharWidth())
137    {
138  14397 drawText(seq, start, end, y1);
139    }
140    }
141   
142    /**
143    * DOCUMENT ME!
144    *
145    * @param seq
146    * DOCUMENT ME!
147    * @param start
148    * DOCUMENT ME!
149    * @param end
150    * DOCUMENT ME!
151    * @param x1
152    * DOCUMENT ME!
153    * @param y1
154    * DOCUMENT ME!
155    * @param width
156    * DOCUMENT ME!
157    * @param height
158    * DOCUMENT ME!
159    */
 
160  14397 toggle public synchronized void drawBoxes(SequenceI seq, int start, int end,
161    int y1)
162    {
163  14397 Color resBoxColour = Color.white;
164   
165  14397 if (seq == null)
166    {
167  0 return; // fix for racecondition
168    }
169  14397 int i = start;
170  14397 int length = seq.getLength();
171   
172  14397 int curStart = -1;
173  14397 int curWidth = av.getCharWidth(), avWidth = av.getCharWidth(),
174    avHeight = av.getCharHeight();
175   
176  14397 Color tempColour = null;
177   
178  812233 while (i <= end)
179    {
180  797836 resBoxColour = Color.white;
181   
182  797836 if (i < length)
183    {
184  797240 SequenceGroup currentSequenceGroup = resColourFinder
185    .getCurrentSequenceGroup(allGroups, i);
186  797240 if (currentSequenceGroup != null)
187    {
188  425600 if (currentSequenceGroup.getDisplayBoxes())
189    {
190  425600 resBoxColour = resColourFinder.getBoxColour(
191    currentSequenceGroup.getGroupColourScheme(), seq, i);
192    }
193    }
194  371640 else if (av.getShowBoxes())
195    {
196  371640 resBoxColour = resColourFinder
197    .getBoxColour(av.getResidueShading(), seq, i);
198    }
199    }
200   
201  797836 if (resBoxColour != tempColour)
202    {
203  379666 if (tempColour != null)
204    {
205  365269 graphics.fillRect(avWidth * (curStart - start), y1, curWidth,
206    avHeight);
207    }
208   
209  379666 graphics.setColor(resBoxColour);
210   
211  379666 curStart = i;
212  379666 curWidth = avWidth;
213  379666 tempColour = resBoxColour;
214    }
215    else
216    {
217  418170 curWidth += avWidth;
218    }
219   
220  797836 i++;
221    }
222   
223  14397 graphics.fillRect(avWidth * (curStart - start), y1, curWidth, avHeight);
224   
225    }
226   
227    /**
228    * DOCUMENT ME!
229    *
230    * @param seq
231    * DOCUMENT ME!
232    * @param start
233    * DOCUMENT ME!
234    * @param end
235    * DOCUMENT ME!
236    * @param x1
237    * DOCUMENT ME!
238    * @param y1
239    * DOCUMENT ME!
240    * @param width
241    * DOCUMENT ME!
242    * @param height
243    * DOCUMENT ME!
244    */
 
245  14397 toggle public void drawText(SequenceI seq, int start, int end, int y1)
246    {
247  14397 y1 += av.getCharHeight() - av.getCharHeight() / 5; // height/5 replaces pady
248  14397 int charOffset = 0;
249  14397 char s;
250   
251  14397 if (end + 1 >= seq.getLength())
252    {
253  1308 end = seq.getLength() - 1;
254    }
255  14397 graphics.setColor(av.getTextColour());
256   
257  14397 boolean drawAllText = monospacedFont && av.getShowText()
258    && allGroups.length == 0 && !av.getColourText()
259    && av.getThresholdTextColour() == 0;
260   
261    /*
262    * EPS or SVG misaligns monospaced strings (JAL-3239)
263    * so always draw these one character at a time
264    */
265  14397 if (graphics instanceof EpsGraphics2D
266    || graphics instanceof SVGGraphics2D)
267    {
268  210 drawAllText = false;
269    }
270  14397 if (drawAllText)
271    {
272  0 if (av.isRenderGaps())
273    {
274  0 graphics.drawString(seq.getSequenceAsString(start, end + 1), 0, y1);
275    }
276    else
277    {
278  0 char gap = av.getGapCharacter();
279  0 graphics.drawString(
280    seq.getSequenceAsString(start, end + 1).replace(gap, ' '),
281    0, y1);
282    }
283    }
284    else
285    {
286  14397 boolean srep = av.isDisplayReferenceSeq();
287  14397 boolean getboxColour = false;
288  14397 boolean isarep = av.getAlignment().getSeqrep() == seq;
289  14397 Color resBoxColour = Color.white;
290   
291  811637 for (int i = start; i <= end; i++)
292    {
293   
294  797240 graphics.setColor(av.getTextColour());
295  797240 getboxColour = false;
296  797240 s = seq.getCharAt(i);
297   
298  797240 if (!renderGaps && jalview.util.Comparison.isGap(s))
299    {
300  0 continue;
301    }
302   
303  797240 SequenceGroup currentSequenceGroup = resColourFinder
304    .getCurrentSequenceGroup(allGroups, i);
305  797240 if (currentSequenceGroup != null)
306    {
307  425600 if (!currentSequenceGroup.getDisplayText())
308    {
309  0 continue;
310    }
311   
312  425600 if (currentSequenceGroup.thresholdTextColour > 0
313    || currentSequenceGroup.getColourText())
314    {
315  0 getboxColour = true;
316  0 resBoxColour = resColourFinder.getBoxColour(
317    currentSequenceGroup.getGroupColourScheme(), seq, i);
318   
319  0 if (currentSequenceGroup.getColourText())
320    {
321  0 graphics.setColor(resBoxColour.darker());
322    }
323   
324  0 if (currentSequenceGroup.thresholdTextColour > 0)
325    {
326  0 if (resBoxColour.getRed() + resBoxColour.getBlue()
327    + resBoxColour
328    .getGreen() < currentSequenceGroup.thresholdTextColour)
329    {
330  0 graphics.setColor(currentSequenceGroup.textColour2);
331    }
332    }
333    }
334    else
335    {
336  425600 graphics.setColor(currentSequenceGroup.textColour);
337    }
338  425600 boolean isgrep = currentSequenceGroup != null
339    ? currentSequenceGroup.getSeqrep() == seq
340    : false;
341  425600 if (!isarep && !isgrep
342    && currentSequenceGroup.getShowNonconserved()) // todo
343    // optimize
344    {
345    // todo - use sequence group consensus
346  0 s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
347   
348    }
349   
350    }
351    else
352    {
353  371640 if (!av.getShowText())
354    {
355  0 continue;
356    }
357   
358  371640 if (av.getColourText())
359    {
360  0 getboxColour = true;
361  0 resBoxColour = resColourFinder
362    .getBoxColour(av.getResidueShading(), seq, i);
363   
364  0 if (av.getShowBoxes())
365    {
366  0 graphics.setColor(resBoxColour.darker());
367    }
368    else
369    {
370  0 graphics.setColor(resBoxColour);
371    }
372    }
373   
374  371640 if (av.getThresholdTextColour() > 0)
375    {
376  0 if (!getboxColour)
377    {
378  0 resBoxColour = resColourFinder
379    .getBoxColour(av.getResidueShading(), seq, i);
380    }
381   
382  0 if (resBoxColour.getRed() + resBoxColour.getBlue()
383    + resBoxColour.getGreen() < av.getThresholdTextColour())
384    {
385  0 graphics.setColor(av.getTextColour2());
386    }
387    }
388  371640 if (!isarep && av.getShowUnconserved())
389    {
390  0 s = getDisplayChar(srep, i, s, '.', null);
391   
392    }
393   
394    }
395   
396  797240 charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
397  797240 graphics.drawString(String.valueOf(s),
398    charOffset + av.getCharWidth() * (i - start), y1);
399   
400    }
401    }
402    }
403   
404    /**
405    * Returns 'conservedChar' to represent the given position if the sequence
406    * character at that position is equal to the consensus (ignoring case), else
407    * returns the sequence character
408    *
409    * @param usesrep
410    * @param position
411    * @param sequenceChar
412    * @param conservedChar
413    * @return
414    */
 
415  0 toggle private char getDisplayChar(final boolean usesrep, int position,
416    char sequenceChar, char conservedChar, SequenceGroup currentGroup)
417    {
418    // TODO - use currentSequenceGroup rather than alignment
419    // currentSequenceGroup.getConsensus()
420  0 char conschar = (usesrep) ? (currentGroup == null
421    || position < currentGroup.getStartRes()
422    || position > currentGroup.getEndRes()
423    ? av.getAlignment().getSeqrep().getCharAt(position)
424  0 : (currentGroup.getSeqrep() != null
425    ? currentGroup.getSeqrep().getCharAt(position)
426    : av.getAlignment().getSeqrep()
427    .getCharAt(position)))
428  0 : (currentGroup != null && currentGroup.getConsensus() != null
429    && position >= currentGroup.getStartRes()
430    && position <= currentGroup.getEndRes()
431    && currentGroup
432    .getConsensus().annotations.length > position)
433    ? currentGroup
434    .getConsensus().annotations[position].displayCharacter
435    .charAt(0)
436    : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
437    .charAt(0);
438  0 if (!jalview.util.Comparison.isGap(conschar)
439    && (sequenceChar == conschar
440    || sequenceChar + CHAR_TO_UPPER == conschar))
441    {
442  0 sequenceChar = conservedChar;
443    }
444  0 return sequenceChar;
445    }
446   
447    /**
448    * DOCUMENT ME!
449    *
450    * @param seq
451    * DOCUMENT ME!
452    * @param start
453    * DOCUMENT ME!
454    * @param end
455    * DOCUMENT ME!
456    * @param x1
457    * DOCUMENT ME!
458    * @param y1
459    * DOCUMENT ME!
460    * @param width
461    * DOCUMENT ME!
462    * @param height
463    * DOCUMENT ME!
464    */
 
465  14 toggle public void drawHighlightedText(SequenceI seq, int start, int end, int x1,
466    int y1)
467    {
468  14 int pady = av.getCharHeight() / 5;
469  14 int charOffset = 0;
470  14 graphics.setColor(Color.BLACK);
471  14 graphics.fillRect(x1, y1, av.getCharWidth() * (end - start + 1),
472    av.getCharHeight());
473  14 graphics.setColor(Color.white);
474   
475  14 char s = '~';
476   
477    // Need to find the sequence position here.
478  14 if (av.isValidCharWidth())
479    {
480  64 for (int i = start; i <= end; i++)
481    {
482  50 if (i < seq.getLength())
483    {
484  50 s = seq.getCharAt(i);
485    }
486   
487  50 charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
488  50 graphics.drawString(String.valueOf(s),
489    charOffset + x1 + (av.getCharWidth() * (i - start)),
490    (y1 + av.getCharHeight()) - pady);
491    }
492    }
493    }
494   
495    /**
496    * Draw a sequence canvas cursor
497    *
498    * @param g
499    * graphics context to draw on
500    * @param s
501    * character to draw at cursor
502    * @param x1
503    * x position of cursor in graphics context
504    * @param y1
505    * y position of cursor in graphics context
506    */
 
507  0 toggle public void drawCursor(Graphics g, char s, int x1, int y1)
508    {
509  0 int pady = av.getCharHeight() / 5;
510  0 int charOffset = 0;
511  0 g.setColor(Color.black);
512  0 g.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
513   
514  0 if (av.isValidCharWidth())
515    {
516  0 g.setColor(Color.white);
517  0 charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
518  0 g.drawString(String.valueOf(s), charOffset + x1,
519    (y1 + av.getCharHeight()) - pady);
520    }
521   
522    }
523    }