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