Clover icon

Coverage Report

  1. Project Clover database Mon Nov 18 2024 09:38:20 GMT
  2. Package jalview.gui

File IdCanvas.java

 

Coverage histogram

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

Code metrics

84
185
16
1
647
395
73
0.39
11.56
16
4.56

Classes

Class Line # Actions
IdCanvas 47 185 73
0.4315789343.2%
 

Contributing tests

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