Clover icon

Coverage Report

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

File IdCanvas.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

76
173
12
1
588
359
65
0.38
14.42
12
5.42

Classes

Class Line # Actions
IdCanvas 46 173 65
0.8390804583.9%
 

Contributing tests

This file is covered by 101 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 java.awt.BorderLayout;
24    import java.awt.Color;
25    import java.awt.Font;
26    import java.awt.FontMetrics;
27    import java.awt.Graphics;
28    import java.awt.Graphics2D;
29    import java.awt.RenderingHints;
30    import java.awt.image.BufferedImage;
31    import java.beans.PropertyChangeEvent;
32    import java.util.List;
33   
34    import javax.swing.JPanel;
35   
36    import jalview.datamodel.SequenceI;
37    import jalview.viewmodel.ViewportListenerI;
38    import jalview.viewmodel.ViewportRanges;
39   
40    /**
41    * DOCUMENT ME!
42    *
43    * @author $author$
44    * @version $Revision$
45    */
 
46    public class IdCanvas extends JPanel implements ViewportListenerI
47    {
48    protected AlignViewport av;
49   
50    protected boolean showScores = true;
51   
52    protected int maxIdLength = -1;
53   
54    protected String maxIdStr = null;
55   
56    BufferedImage image;
57   
58    // Graphics2D gg;
59   
60    int imgHeight = 0;
61   
62    boolean fastPaint = false;
63   
64    List<SequenceI> searchResults;
65   
66    AnnotationPanel ap;
67   
68    private Font idfont;
69   
70    /**
71    * Creates a new IdCanvas object.
72    *
73    * @param av
74    * DOCUMENT ME!
75    */
 
76  267 toggle public IdCanvas(AlignViewport av)
77    {
78  267 setLayout(new BorderLayout());
79  267 this.av = av;
80  267 PaintRefresher.Register(this, av.getSequenceSetId());
81  267 av.getRanges().addPropertyChangeListener(this);
82    }
83   
84    /**
85    * DOCUMENT ME!
86    *
87    * @param g
88    * DOCUMENT ME!
89    * @param hiddenRows
90    * true - check and display hidden row marker if need be
91    * @param s
92    * DOCUMENT ME!
93    * @param i
94    * DOCUMENT ME!
95    * @param starty
96    * DOCUMENT ME!
97    * @param ypos
98    * DOCUMENT ME!
99    */
 
100  532 toggle public void drawIdString(Graphics2D g, boolean hiddenRows, SequenceI s,
101    int i, int starty, int ypos)
102    {
103  532 int xPos = 0;
104  532 int panelWidth = getWidth();
105  532 int charHeight = av.getCharHeight();
106   
107  532 if ((searchResults != null) && searchResults.contains(s))
108    {
109  0 g.setColor(Color.black);
110  0 g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
111    charHeight);
112  0 g.setColor(Color.white);
113    }
114  532 else if ((av.getSelectionGroup() != null)
115    && av.getSelectionGroup().getSequences(null).contains(s))
116    {
117  0 g.setColor(Color.lightGray);
118  0 g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
119    charHeight);
120  0 g.setColor(Color.white);
121    }
122    else
123    {
124  532 g.setColor(av.getSequenceColour(s));
125  532 g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
126    charHeight);
127  532 g.setColor(Color.black);
128    }
129   
130  532 if (av.isRightAlignIds())
131    {
132  0 FontMetrics fm = g.getFontMetrics();
133  0 xPos = panelWidth
134    - fm.stringWidth(s.getDisplayId(av.getShowJVSuffix())) - 4;
135    }
136   
137  532 g.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos,
138    (((i - starty + 1) * charHeight) + ypos) - (charHeight / 5));
139   
140  532 if (hiddenRows && av.getShowHiddenMarkers())
141    {
142  472 drawMarker(g, av, i, starty, ypos);
143    }
144   
145    }
146   
147    /**
148    * DOCUMENT ME!
149    *
150    * @param vertical
151    * DOCUMENT ME!
152    */
 
153  6 toggle public void fastPaint(int vertical)
154    {
155   
156    /*
157    * for now, not attempting fast paint of wrapped ids...
158    */
159  6 if (image == null || av.getWrapAlignment())
160    {
161  5 repaint();
162   
163  5 return;
164    }
165   
166  1 ViewportRanges ranges = av.getRanges();
167   
168  1 Graphics2D gg = image.createGraphics();
169  1 gg.copyArea(0, 0, getWidth(), imgHeight, 0,
170    -vertical * av.getCharHeight());
171   
172  1 int ss = ranges.getStartSeq();
173  1 int es = ranges.getEndSeq();
174  1 int transY = 0;
175   
176  1 if (vertical > 0) // scroll down
177    {
178  1 ss = es - vertical;
179   
180  1 if (ss < ranges.getStartSeq())
181    { // ie scrolling too fast, more than a page at a time
182  1 ss = ranges.getStartSeq();
183    }
184    else
185    {
186  0 transY = imgHeight - ((vertical + 1) * av.getCharHeight());
187    }
188    }
189  0 else if (vertical < 0) // scroll up
190    {
191  0 es = ss - vertical;
192   
193  0 if (es > ranges.getEndSeq())
194    {
195  0 es = ranges.getEndSeq();
196    }
197    }
198   
199  1 gg.translate(0, transY);
200   
201  1 drawIds(gg, av, ss, es, searchResults);
202   
203  1 gg.translate(0, -transY);
204   
205  1 gg.dispose();
206   
207  1 fastPaint = true;
208   
209    // Call repaint on alignment panel so that repaints from other alignment
210    // panel components can be aggregated. Otherwise performance of the overview
211    // window and others may be adversely affected.
212  1 av.getAlignPanel().repaint();
213    }
214   
215    /**
216    * DOCUMENT ME!
217    *
218    * @param g
219    * DOCUMENT ME!
220    */
 
221  896 toggle @Override
222    public void paintComponent(Graphics g)
223    {
224  896 g.setColor(Color.white);
225  896 g.fillRect(0, 0, getWidth(), getHeight());
226   
227  896 if (fastPaint)
228    {
229  1 fastPaint = false;
230  1 g.drawImage(image, 0, 0, this);
231   
232  1 return;
233    }
234   
235  895 int oldHeight = imgHeight;
236   
237  895 imgHeight = getHeight();
238  895 imgHeight -= (imgHeight % av.getCharHeight());
239   
240  895 if (imgHeight < 1)
241    {
242  0 return;
243    }
244   
245  895 if (oldHeight != imgHeight || image.getWidth(this) != getWidth())
246    {
247  93 image = new BufferedImage(getWidth(), imgHeight,
248    BufferedImage.TYPE_INT_RGB);
249    }
250   
251  895 Graphics2D gg = image.createGraphics();
252   
253    // Fill in the background
254  895 gg.setColor(Color.white);
255  895 gg.fillRect(0, 0, getWidth(), imgHeight);
256   
257  895 drawIds(gg, av, av.getRanges().getStartSeq(), av.getRanges().getEndSeq(), searchResults);
258   
259  895 gg.dispose();
260   
261  895 g.drawImage(image, 0, 0, this);
262    }
263   
264    /**
265    * Draws sequence ids from sequence index startSeq to endSeq (inclusive), with
266    * the font and other display settings configured on the viewport. Ids of
267    * sequences included in the selection are coloured grey, otherwise the
268    * current id colour for the sequence id is used.
269    *
270    * @param g
271    * @param alignViewport
272    * @param startSeq
273    * @param endSeq
274    * @param selection
275    */
 
276  904 toggle void drawIds(Graphics2D g, AlignViewport alignViewport, final int startSeq,
277    final int endSeq, List<SequenceI> selection)
278    {
279  904 Font font = alignViewport.getFont();
280  904 if (alignViewport.isSeqNameItalics())
281    {
282  904 setIdfont(new Font(font.getName(), Font.ITALIC,
283    font.getSize()));
284    }
285    else
286    {
287  0 setIdfont(font);
288    }
289   
290  904 g.setFont(getIdfont());
291  904 FontMetrics fm = g.getFontMetrics();
292   
293  904 if (alignViewport.antiAlias)
294    {
295  8 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
296    RenderingHints.VALUE_ANTIALIAS_ON);
297    }
298   
299  904 Color currentColor = Color.white;
300  904 Color currentTextColor = Color.black;
301   
302  904 boolean hasHiddenRows = alignViewport.hasHiddenRows();
303   
304  904 if (alignViewport.getWrapAlignment())
305    {
306  122 drawIdsWrapped(g, alignViewport, startSeq, getHeight());
307  122 return;
308    }
309   
310    // Now draw the id strings
311  782 int panelWidth = getWidth();
312  782 int xPos = 0;
313   
314    // Now draw the id strings
315  8378 for (int i = startSeq; i <= endSeq; i++)
316    {
317  7596 SequenceI sequence = alignViewport.getAlignment().getSequenceAt(i);
318   
319  7596 if (sequence == null)
320    {
321  0 continue;
322    }
323   
324  7596 if (hasHiddenRows || alignViewport.isDisplayReferenceSeq())
325    {
326  4148 g.setFont(getHiddenFont(sequence, alignViewport));
327  4148 fm = g.getFontMetrics();
328    }
329   
330    // Selected sequence colours
331  7596 if (selection != null && selection.contains(sequence))
332    {
333  0 currentColor = Color.black;
334  0 currentTextColor = Color.white;
335    }
336  7596 else if ((alignViewport.getSelectionGroup() != null) && alignViewport
337    .getSelectionGroup().getSequences(null).contains(sequence))
338    {
339  13 currentColor = Color.lightGray;
340  13 currentTextColor = Color.black;
341    }
342    else
343    {
344  7583 currentColor = alignViewport.getSequenceColour(sequence);
345  7583 currentTextColor = Color.black;
346    }
347   
348  7596 g.setColor(currentColor);
349   
350  7596 int charHeight = alignViewport.getCharHeight();
351  7596 g.fillRect(0, (i - startSeq) * charHeight,
352    getWidth(), charHeight);
353   
354  7596 g.setColor(currentTextColor);
355   
356  7596 String string = sequence
357    .getDisplayId(alignViewport.getShowJVSuffix());
358   
359  7596 if (alignViewport.isRightAlignIds())
360    {
361  0 xPos = panelWidth - fm.stringWidth(string) - 4;
362    }
363   
364  7596 g.drawString(string, xPos, (((i - startSeq) * charHeight) + charHeight)
365    - (charHeight / 5));
366   
367  7596 if (hasHiddenRows && av.getShowHiddenMarkers())
368    {
369  4148 drawMarker(g, alignViewport, i, startSeq, 0);
370    }
371    }
372    }
373   
374    /**
375    * Draws sequence ids, and annotation labels if annotations are shown, in
376    * wrapped mode
377    *
378    * @param g
379    * @param alignViewport
380    * @param startSeq
381    */
 
382  122 toggle void drawIdsWrapped(Graphics2D g, AlignViewport alignViewport,
383    int startSeq, int pageHeight)
384    {
385  122 int alignmentWidth = alignViewport.getAlignment().getWidth();
386  122 final int alheight = alignViewport.getAlignment().getHeight();
387   
388    /*
389    * assumption: SeqCanvas.calculateWrappedGeometry has been called
390    */
391  122 SeqCanvas seqCanvas = alignViewport.getAlignPanel()
392    .getSeqPanel().seqCanvas;
393   
394  122 final int charHeight = alignViewport.getCharHeight();
395   
396  122 AnnotationLabels labels = null;
397  122 if (alignViewport.isShowAnnotation())
398    {
399  122 labels = new AnnotationLabels(alignViewport);
400    }
401   
402  122 ViewportRanges ranges = alignViewport.getRanges();
403   
404  122 int rowSize = ranges.getViewportWidth();
405   
406    /*
407    * draw repeating sequence ids until out of sequence data or
408    * out of visible space, whichever comes first
409    */
410  122 boolean hasHiddenRows = alignViewport.hasHiddenRows();
411  122 int ypos = seqCanvas.wrappedSpaceAboveAlignment;
412  122 int rowStartRes = ranges.getStartRes();
413  362 while ((ypos <= pageHeight) && (rowStartRes < alignmentWidth))
414    {
415  772 for (int i = startSeq; i < alheight; i++)
416    {
417  532 SequenceI s = alignViewport.getAlignment().getSequenceAt(i);
418  532 if (hasHiddenRows || alignViewport.isDisplayReferenceSeq())
419    {
420  472 g.setFont(getHiddenFont(s, alignViewport));
421    }
422    else
423    {
424  60 g.setFont(getIdfont());
425    }
426  532 drawIdString(g, hasHiddenRows, s, i, 0, ypos);
427    }
428   
429  240 if (labels != null && alignViewport.isShowAnnotation())
430    {
431  240 g.translate(0, ypos + (alheight * charHeight));
432  240 labels.drawComponent(g, getWidth());
433  240 g.translate(0, -ypos - (alheight * charHeight));
434    }
435   
436  240 ypos += seqCanvas.wrappedRepeatHeightPx;
437  240 rowStartRes += rowSize;
438    }
439    }
440   
441    /**
442    * Draws a marker (a blue right-pointing triangle) between sequences to
443    * indicate hidden sequences.
444    *
445    * @param g
446    * @param alignViewport
447    * @param seqIndex
448    * @param starty
449    * @param yoffset
450    */
 
451  4620 toggle void drawMarker(Graphics2D g, AlignViewport alignViewport, int seqIndex, int starty, int yoffset)
452    {
453  4620 SequenceI[] hseqs = alignViewport.getAlignment()
454    .getHiddenSequences().hiddenSequences;
455    // Use this method here instead of calling hiddenSeq adjust
456    // 3 times.
457  4620 int hSize = hseqs.length;
458   
459  4620 int hiddenIndex = seqIndex;
460  4620 int lastIndex = seqIndex - 1;
461  4620 int nextIndex = seqIndex + 1;
462   
463  78252 for (int j = 0; j < hSize; j++)
464    {
465  73632 if (hseqs[j] != null)
466    {
467  13756 if (j - 1 < hiddenIndex)
468    {
469  705 hiddenIndex++;
470    }
471  13756 if (j - 1 < lastIndex)
472    {
473  438 lastIndex++;
474    }
475  13756 if (j - 1 < nextIndex)
476    {
477  4606 nextIndex++;
478    }
479    }
480    }
481   
482    /*
483    * are we below or above the hidden sequences?
484    */
485  4620 boolean below = (hiddenIndex > lastIndex + 1);
486  4620 boolean above = (nextIndex > hiddenIndex + 1);
487   
488  4620 g.setColor(Color.blue);
489  4620 int charHeight = av.getCharHeight();
490   
491    /*
492    * vertices of the triangle, below or above hidden seqs
493    */
494  4620 int[] xPoints = new int[]
495    { getWidth() - charHeight,
496    getWidth() - charHeight, getWidth() };
497  4620 int yShift = seqIndex - starty;
498   
499  4620 if (below)
500    {
501  261 int[] yPoints = new int[] { yShift * charHeight + yoffset,
502    yShift * charHeight + yoffset + charHeight / 4,
503    yShift * charHeight + yoffset };
504  261 g.fillPolygon(xPoints, yPoints, 3);
505    }
506  4620 if (above)
507    {
508  599 yShift++;
509  599 int[] yPoints = new int[] { yShift * charHeight + yoffset,
510    yShift * charHeight + yoffset - charHeight / 4,
511    yShift * charHeight + yoffset };
512  599 g.fillPolygon(xPoints, yPoints, 3);
513    }
514    }
515   
516    /**
517    * Answers the standard sequence id font, or a bold font if the sequence is
518    * set as reference or a hidden group representative
519    *
520    * @param seq
521    * @param alignViewport
522    * @return
523    */
 
524  4620 toggle private Font getHiddenFont(SequenceI seq, AlignViewport alignViewport)
525    {
526  4620 if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
527    {
528  165 return new Font(av.getFont().getName(), Font.BOLD,
529    av.getFont().getSize());
530    }
531  4455 return getIdfont();
532    }
533   
534    /**
535    * DOCUMENT ME!
536    *
537    * @param list
538    * DOCUMENT ME!
539    */
 
540  0 toggle public void setHighlighted(List<SequenceI> list)
541    {
542  0 searchResults = list;
543  0 repaint();
544    }
545   
 
546  5419 toggle public Font getIdfont()
547    {
548  5419 return idfont;
549    }
550   
 
551  904 toggle public void setIdfont(Font idfont)
552    {
553  904 this.idfont = idfont;
554    }
555   
556    /**
557    * Respond to viewport range changes (e.g. alignment panel was scrolled). Both
558    * scrolling and resizing change viewport ranges. Scrolling changes both start
559    * and end points, but resize only changes end values. Here we only want to
560    * fastpaint on a scroll, with resize using a normal paint, so scroll events
561    * are identified as changes to the horizontal or vertical start value.
562    * <p>
563    * In unwrapped mode, only responds to a vertical scroll, as horizontal scroll
564    * leaves sequence ids unchanged. In wrapped mode, only vertical scroll is
565    * provided, but it generates a change of "startres" which does require an
566    * update here.
567    */
 
568  406 toggle @Override
569    public void propertyChange(PropertyChangeEvent evt)
570    {
571  406 String propertyName = evt.getPropertyName();
572  406 if (propertyName.equals(ViewportRanges.STARTSEQ)
573    || (av.getWrapAlignment()
574    && propertyName.equals(ViewportRanges.STARTRES)))
575    {
576  6 fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
577    }
578  400 else if (propertyName.equals(ViewportRanges.STARTRESANDSEQ))
579    {
580  0 fastPaint(((int[]) evt.getNewValue())[1]
581    - ((int[]) evt.getOldValue())[1]);
582    }
583  400 else if (propertyName.equals(ViewportRanges.MOVE_VIEWPORT))
584    {
585  0 repaint();
586    }
587    }
588    }