Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.gui

File SequenceRenderer.java

 

Coverage histogram

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

Code metrics

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