73aeb79fe5241b0210fc7726a45de621e777704d
[jalview.git] / test / jalview / gui / SeqCanvasTest.java
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 static org.testng.Assert.assertEquals;
24
25 import jalview.datamodel.AlignmentI;
26 import jalview.io.DataSourceType;
27 import jalview.io.FileLoader;
28
29 import java.awt.Font;
30 import java.awt.FontMetrics;
31
32 import org.testng.annotations.Test;
33
34 import junit.extensions.PA;
35
36 public class SeqCanvasTest
37 {
38   /**
39    * Test the method that computes wrapped width in residues, height of wrapped
40    * widths in pixels, and the number of widths visible
41    */
42   @Test(groups = "Functional")
43   public void testCalculateWrappedGeometry_noAnnotations()
44   {
45     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
46             "examples/uniref50.fa", DataSourceType.FILE);
47     AlignViewport av = af.getViewport();
48     AlignmentI al = av.getAlignment();
49     assertEquals(al.getWidth(), 157);
50     assertEquals(al.getHeight(), 15);
51     av.getRanges().setStartEndSeq(0, 14);
52
53     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
54
55     av.setWrapAlignment(true);
56     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
57     int charHeight = av.getCharHeight();
58     int charWidth = av.getCharWidth();
59     assertEquals(charHeight, 17);
60     assertEquals(charWidth, 12);
61
62     /*
63      * first with scales above, left, right
64      */
65     av.setShowAnnotation(false);
66     av.setScaleAboveWrapped(true);
67     av.setScaleLeftWrapped(true);
68     av.setScaleRightWrapped(true);
69     FontMetrics fm = testee.getFontMetrics(av.getFont());
70     int labelWidth = fm.stringWidth("000") + charWidth;
71     assertEquals(labelWidth, 39); // 3 x 9 + charWidth
72
73     /*
74      * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
75      * take the whole multiple of character widths
76      */
77     int canvasWidth = 400;
78     int canvasHeight = 300;
79     int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
80     int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
81     assertEquals(wrappedWidth, residueColumns);
82     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
83     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
84     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
85             2 * charHeight);
86     int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
87     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
88     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
89
90     /*
91      * repeat height is 17 * (2 + 15) = 289
92      * make canvas height 2 * 289 + 3 * charHeight so just enough to
93      * draw 2 widths and the first sequence of a third
94      */
95     canvasHeight = charHeight * (17 * 2 + 3);
96     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
97     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
98
99     /*
100      * reduce canvas height by 1 pixel 
101      * - should not be enough height to draw 3 widths
102      */
103     canvasHeight -= 1;
104     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
105     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
106
107     /*
108      * turn off scale above - can now fit in 2 and a bit widths
109      */
110     av.setScaleAboveWrapped(false);
111     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
112     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
113
114     /*
115      * reduce height to enough for 2 widths and not quite a third
116      * i.e. two repeating heights + spacer + sequence - 1 pixel
117      */
118     canvasHeight = charHeight * (16 * 2 + 2) - 1;
119     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
120     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
121
122     /*
123      * make canvas width enough for scales and 20 residues
124      */
125     canvasWidth = 2 * labelWidth + 20 * charWidth;
126     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
127             canvasHeight);
128     assertEquals(wrappedWidth, 20);
129
130     /*
131      * reduce width by 1 pixel - rounds down to 19 residues
132      */
133     canvasWidth -= 1;
134     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
135             canvasHeight);
136     assertEquals(wrappedWidth, 19);
137
138     /*
139      * turn off West scale - adds labelWidth (39) to available for residues
140      * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
141      */
142     av.setScaleLeftWrapped(false);
143     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
144             canvasHeight);
145     assertEquals(wrappedWidth, 23);
146
147     /*
148      * add 10 pixels to width to fit in another whole residue column
149      */
150     canvasWidth += 9;
151     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
152             canvasHeight);
153     assertEquals(wrappedWidth, 23);
154     canvasWidth += 1;
155     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
156             canvasHeight);
157     assertEquals(wrappedWidth, 24);
158
159     /*
160      * turn off East scale to gain 39 more pixels (3 columns remainder 3)
161      */
162     av.setScaleRightWrapped(false);
163     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
164             canvasHeight);
165     assertEquals(wrappedWidth, 27);
166
167     /*
168      * add 9 pixels to width to gain a residue column
169      */
170     canvasWidth += 8;
171     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
172             canvasHeight);
173     assertEquals(wrappedWidth, 27); // 8px not enough
174     canvasWidth += 1;
175     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
176             canvasHeight);
177     assertEquals(wrappedWidth, 28); // 9px is enough
178
179     /*
180      * now West but not East scale - lose 39 pixels or 4 columns
181      */
182     av.setScaleLeftWrapped(true);
183     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
184             canvasHeight);
185     assertEquals(wrappedWidth, 24);
186
187     /*
188      * adding 3 pixels to width regains one column
189      */
190     canvasWidth += 2;
191     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
192             canvasHeight);
193     assertEquals(wrappedWidth, 24); // 2px not enough
194     canvasWidth += 1;
195     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
196             canvasHeight);
197     assertEquals(wrappedWidth, 25); // 3px is enough
198
199     /*
200      * turn off scales left and right, make width exactly 157 columns
201      */
202     av.setScaleLeftWrapped(false);
203     canvasWidth = al.getWidth() * charWidth;
204     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
205     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
206   }
207
208   /**
209    * Test the method that computes wrapped width in residues, height of wrapped
210    * widths in pixels, and the number of widths visible
211    */
212   @Test(groups = "Functional")
213   public void testCalculateWrappedGeometry_withAnnotations()
214   {
215     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
216             "examples/uniref50.fa", DataSourceType.FILE);
217     AlignViewport av = af.getViewport();
218     AlignmentI al = av.getAlignment();
219     assertEquals(al.getWidth(), 157);
220     assertEquals(al.getHeight(), 15);
221   
222     av.setWrapAlignment(true);
223     av.getRanges().setStartEndSeq(0, 14);
224     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
225     int charHeight = av.getCharHeight();
226     int charWidth = av.getCharWidth();
227     assertEquals(charHeight, 17);
228     assertEquals(charWidth, 12);
229   
230     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
231   
232     /*
233      * first with scales above, left, right
234      */
235     av.setShowAnnotation(true);
236     av.setScaleAboveWrapped(true);
237     av.setScaleLeftWrapped(true);
238     av.setScaleRightWrapped(true);
239     FontMetrics fm = testee.getFontMetrics(av.getFont());
240     int labelWidth = fm.stringWidth("000") + charWidth;
241     assertEquals(labelWidth, 39); // 3 x 9 + charWidth
242     int annotationHeight = testee.getAnnotationHeight();
243
244     /*
245      * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
246      * take the whole multiple of character widths
247      */
248     int canvasWidth = 400;
249     int canvasHeight = 300;
250     int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
251     int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
252     assertEquals(wrappedWidth, residueColumns);
253     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
254     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
255     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
256             2 * charHeight);
257     int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
258     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
259             + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight);
260     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
261   
262     /*
263      * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510
264      * make canvas height 2 of these plus 3 charHeights 
265      * so just enough to draw 2 widths, gap + scale + the first sequence of a third
266      */
267     canvasHeight = charHeight * (17 * 2 + 3)
268             + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP);
269     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
270     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
271   
272     /*
273      * reduce canvas height by 1 pixel - should not be enough height
274      * to draw 3 widths
275      */
276     canvasHeight -= 1;
277     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
278     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
279   
280     /*
281      * turn off scale above - can now fit in 2 and a bit widths
282      */
283     av.setScaleAboveWrapped(false);
284     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
285     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
286   
287     /*
288      * reduce height to enough for 2 widths and not quite a third
289      * i.e. two repeating heights + spacer + sequence - 1 pixel
290      */
291     canvasHeight = charHeight * (16 * 2 + 2)
292             + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1;
293     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
294     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
295
296     /*
297      * add 1 pixel to height - should now get 3 widths drawn
298      */
299     canvasHeight += 1;
300     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
301     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
302   }
303
304   /**
305    * Test simulates loading an unwrapped alignment, shrinking it vertically so
306    * not all sequences are visible, then changing to wrapped mode. The ranges
307    * endSeq should be unchanged, but the vertical repeat height should include
308    * all sequences.
309    */
310   @Test(groups = "Functional")
311   public void testCalculateWrappedGeometry_fromScrolled()
312   {
313     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
314             "examples/uniref50.fa", DataSourceType.FILE);
315     AlignViewport av = af.getViewport();
316     AlignmentI al = av.getAlignment();
317     assertEquals(al.getWidth(), 157);
318     assertEquals(al.getHeight(), 15);
319     av.getRanges().setStartEndSeq(0, 3);
320     av.setShowAnnotation(false);
321     av.setScaleAboveWrapped(true);
322
323     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
324
325     av.setWrapAlignment(true);
326     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
327     int charHeight = av.getCharHeight();
328     int charWidth = av.getCharWidth();
329     assertEquals(charHeight, 17);
330     assertEquals(charWidth, 12);
331
332     int canvasWidth = 400;
333     int canvasHeight = 300;
334     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
335
336     assertEquals(av.getRanges().getEndSeq(), 3); // unchanged
337     int repeatingHeight = (int) PA.getValue(testee,
338             "wrappedRepeatHeightPx");
339     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
340   }
341 }