21d67f4ea8cb3e9612ddd1302bf643eed35df344
[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     Cache.loadProperties(null);
47     Cache.initLogger();
48     Desktop.getInstance().setVisible(false);
49   }
50
51   /**
52    * Test the method that computes wrapped width in residues, height of wrapped
53    * widths in pixels, and the number of widths visible
54    */
55   @Test(groups = "Functional")
56   public void testCalculateWrappedGeometry_noAnnotations()
57   {
58     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
59             "examples/uniref50.fa", DataSourceType.FILE);
60     
61     AlignViewport av = af.getViewport();
62     AlignmentI al = av.getAlignment();
63     assertEquals(al.getWidth(), 157);
64     assertEquals(al.getHeight(), 15);
65     av.getRanges().setStartEndSeq(0, 14);
66
67     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
68
69     av.setWrapAlignment(true);
70     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
71     int charHeight = av.getCharHeight();
72     int charWidth = av.getCharWidth();
73     assertEquals(charHeight, !Platform.isWin() ? 17 : 19);
74     assertEquals(charWidth, !Platform.isWin() ? 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.isWin() ? 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.isWin() ? 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     assertEquals(charHeight, !Platform.isWin() ? 17 : 19);
244     assertEquals(charWidth, !Platform.isWin() ? 12 : 11);
245
246     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
247   
248     /*
249      * first with scales above, left, right
250      */
251     av.setShowAnnotation(true);
252     av.setScaleAboveWrapped(true);
253     av.setScaleLeftWrapped(true);
254     av.setScaleRightWrapped(true);
255
256     FontMetrics fm = testee.getFontMetrics(av.getFont());
257     int labelWidth = fm.stringWidth("000") + charWidth;
258     assertEquals(labelWidth,
259             !Platform.isWin() ? 3 * 9 + charWidth : 3 * 8 + charWidth);
260
261     int annotationHeight = testee.getAnnotationHeight();
262
263     /*
264      * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
265      * take the whole multiple of character widths
266      */
267     int canvasWidth = 400;
268     int canvasHeight = 300;
269     int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
270     int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
271     assertEquals(wrappedWidth, residueColumns);
272     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
273     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
274     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
275             2 * charHeight);
276     int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
277     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
278             + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight);
279     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
280   
281     /*
282      * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510
283      * make canvas height 2 of these plus 3 charHeights 
284      * so just enough to draw 2 widths, gap + scale + the first sequence of a third
285      */
286     canvasHeight = charHeight * (17 * 2 + 3)
287             + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP);
288     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
289     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
290   
291     /*
292      * reduce canvas height by 1 pixel - should not be enough height
293      * to draw 3 widths
294      */
295     canvasHeight -= 1;
296     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
297     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
298   
299     /*
300      * turn off scale above - can now fit in 2 and a bit widths
301      */
302     av.setScaleAboveWrapped(false);
303     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
304     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
305   
306     /*
307      * reduce height to enough for 2 widths and not quite a third
308      * i.e. two repeating heights + spacer + sequence - 1 pixel
309      */
310     canvasHeight = charHeight * (16 * 2 + 2)
311             + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1;
312     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
313     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
314
315     /*
316      * add 1 pixel to height - should now get 3 widths drawn
317      */
318     canvasHeight += 1;
319     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
320     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
321   }
322
323   /**
324    * Test simulates loading an unwrapped alignment, shrinking it vertically so
325    * not all sequences are visible, then changing to wrapped mode. The ranges
326    * endSeq should be unchanged, but the vertical repeat height should include
327    * all sequences.
328    */
329   @Test(groups = "Functional")
330   public void testCalculateWrappedGeometry_fromScrolled()
331   {
332     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
333             "examples/uniref50.fa", DataSourceType.FILE);
334     // 
335     System.out.println("ap dim = " + af.alignPanel.getSize());
336     System.out.println("seqpan dim = " + af.alignPanel.getSeqPanel().getSize());
337     System.out.println("seqcan dim = " + af.alignPanel.getSeqPanel().seqCanvas.getSize());
338
339
340     AlignViewport av = af.getViewport();
341     AlignmentI al = av.getAlignment();
342     assertEquals(al.getWidth(), 157);
343     assertEquals(al.getHeight(), 15);
344
345     ViewportRanges ranges = av.getRanges();
346     System.out.println(ranges + " before setting to 3");
347     ranges.setStartEndSeq(0, 3);
348     int endSeq = ranges.getEndSeq();
349     System.out.println(ranges + " after setting to 3");
350     av.setShowAnnotation(false);
351     av.setScaleAboveWrapped(true);
352
353     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
354     av.setWrapAlignment(true);
355     av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
356     int charHeight = av.getCharHeight();
357     int charWidth = av.getCharWidth();
358     // Windows h=19, w=11.
359     assertEquals(charHeight, !Platform.isWin() ? 17 : 19);
360     assertEquals(charWidth, !Platform.isWin() ? 12 : 11);
361     
362     int canvasWidth = 400;
363     int canvasHeight = 300;
364     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
365     System.out.println(ranges);
366     assertEquals(ranges.getEndSeq(), endSeq); // unchanged
367     int repeatingHeight = (int) PA.getValue(testee,
368             "wrappedRepeatHeightPx");
369     int h = charHeight * (2 + al.getHeight());
370     assertEquals(repeatingHeight, h);
371   }
372 }