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