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