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