JAL-3438 spotless for 2.11.2.0
[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 java.awt.Font;
24 import java.awt.FontMetrics;
25
26 import org.testng.annotations.BeforeMethod;
27 import org.testng.annotations.Test;
28 import static org.testng.Assert.assertEquals;
29 import static org.testng.Assert.assertFalse;
30 import static org.testng.Assert.assertNotNull;
31 import static org.testng.Assert.assertNull;
32 import static org.testng.Assert.assertTrue;
33
34 import jalview.bin.Cache;
35 import jalview.datamodel.AlignmentI;
36 import jalview.datamodel.SearchResults;
37 import jalview.datamodel.SearchResultsI;
38 import jalview.io.DataSourceType;
39 import jalview.io.DataSourceType;
40 import jalview.io.FileLoader;
41
42 import junit.extensions.PA;
43
44 public class SeqCanvasTest
45 {
46   private AlignFrame af;
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     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,
89             canvasHeight);
90     assertEquals(wrappedWidth, residueColumns);
91     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
92     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
93     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
94             2 * charHeight);
95     int repeatingHeight = (int) PA.getValue(testee,
96             "wrappedRepeatHeightPx");
97     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
98     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
99
100     /*
101      * repeat height is 17 * (2 + 15) = 289
102      * make canvas height 2 * 289 + 3 * charHeight so just enough to
103      * draw 2 widths and the first sequence of a third
104      */
105     canvasHeight = charHeight * (17 * 2 + 3);
106     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
107     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
108
109     /*
110      * reduce canvas height by 1 pixel 
111      * - should not be enough height to draw 3 widths
112      */
113     canvasHeight -= 1;
114     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
115     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
116
117     /*
118      * turn off scale above - can now fit in 2 and a bit widths
119      */
120     av.setScaleAboveWrapped(false);
121     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
122     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
123
124     /*
125      * reduce height to enough for 2 widths and not quite a third
126      * i.e. two repeating heights + spacer + sequence - 1 pixel
127      */
128     canvasHeight = charHeight * (16 * 2 + 2) - 1;
129     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
130     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
131
132     /*
133      * make canvas width enough for scales and 20 residues
134      */
135     canvasWidth = 2 * labelWidth + 20 * charWidth;
136     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
137             canvasHeight);
138     assertEquals(wrappedWidth, 20);
139
140     /*
141      * reduce width by 1 pixel - rounds down to 19 residues
142      */
143     canvasWidth -= 1;
144     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
145             canvasHeight);
146     assertEquals(wrappedWidth, 19);
147
148     /*
149      * turn off West scale - adds labelWidth (39) to available for residues
150      * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
151      */
152     av.setScaleLeftWrapped(false);
153     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
154             canvasHeight);
155     assertEquals(wrappedWidth, 23);
156
157     /*
158      * add 10 pixels to width to fit in another whole residue column
159      */
160     canvasWidth += 9;
161     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
162             canvasHeight);
163     assertEquals(wrappedWidth, 23);
164     canvasWidth += 1;
165     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
166             canvasHeight);
167     assertEquals(wrappedWidth, 24);
168
169     /*
170      * turn off East scale to gain 39 more pixels (3 columns remainder 3)
171      */
172     av.setScaleRightWrapped(false);
173     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
174             canvasHeight);
175     assertEquals(wrappedWidth, 27);
176
177     /*
178      * add 9 pixels to width to gain a residue column
179      */
180     canvasWidth += 8;
181     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
182             canvasHeight);
183     assertEquals(wrappedWidth, 27); // 8px not enough
184     canvasWidth += 1;
185     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
186             canvasHeight);
187     assertEquals(wrappedWidth, 28); // 9px is enough
188
189     /*
190      * now West but not East scale - lose 39 pixels or 4 columns
191      */
192     av.setScaleLeftWrapped(true);
193     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
194             canvasHeight);
195     assertEquals(wrappedWidth, 24);
196
197     /*
198      * adding 3 pixels to width regains one column
199      */
200     canvasWidth += 2;
201     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
202             canvasHeight);
203     assertEquals(wrappedWidth, 24); // 2px not enough
204     canvasWidth += 1;
205     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
206             canvasHeight);
207     assertEquals(wrappedWidth, 25); // 3px is enough
208
209     /*
210      * turn off scales left and right, make width exactly 157 columns
211      */
212     av.setScaleLeftWrapped(false);
213     canvasWidth = al.getWidth() * charWidth;
214     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
215     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
216   }
217
218   /**
219    * Test the method that computes wrapped width in residues, height of wrapped
220    * widths in pixels, and the number of widths visible
221    */
222   @Test(groups = "Functional")
223   public void testCalculateWrappedGeometry_withAnnotations()
224   {
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,
260             canvasHeight);
261     assertEquals(wrappedWidth, residueColumns);
262     assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
263     assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
264     assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
265             2 * charHeight);
266     int repeatingHeight = (int) PA.getValue(testee,
267             "wrappedRepeatHeightPx");
268     assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
269             + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight);
270     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
271
272     /*
273      * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510
274      * make canvas height 2 of these plus 3 charHeights 
275      * so just enough to draw 2 widths, gap + scale + the first sequence of a third
276      */
277     canvasHeight = charHeight * (17 * 2 + 3)
278             + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP);
279     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
280     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
281
282     /*
283      * reduce canvas height by 1 pixel - should not be enough height
284      * to draw 3 widths
285      */
286     canvasHeight -= 1;
287     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
288     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
289
290     /*
291      * turn off scale above - can now fit in 2 and a bit widths
292      */
293     av.setScaleAboveWrapped(false);
294     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
295     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
296
297     /*
298      * reduce height to enough for 2 widths and not quite a third
299      * i.e. two repeating heights + spacer + sequence - 1 pixel
300      */
301     canvasHeight = charHeight * (16 * 2 + 2)
302             + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1;
303     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
304     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
305
306     /*
307      * add 1 pixel to height - should now get 3 widths drawn
308      */
309     canvasHeight += 1;
310     testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
311     assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
312   }
313
314   /**
315    * Test simulates loading an unwrapped alignment, shrinking it vertically so
316    * not all sequences are visible, then changing to wrapped mode. The ranges
317    * endSeq should be unchanged, but the vertical repeat height should include
318    * all sequences.
319    */
320   @Test(groups = "Functional_Failing")
321   public void testCalculateWrappedGeometry_fromScrolled()
322   {
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.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
329     av.setWrapAlignment(true);
330     av.setShowAnnotation(false);
331     av.setScaleAboveWrapped(true);
332
333     SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
334
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
350   @BeforeMethod(alwaysRun = true)
351   public void setUp()
352   {
353     Cache.loadProperties("test/jalview/io/testProps.jvprops");
354     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
355             Boolean.TRUE.toString());
356     af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
357             DataSourceType.FILE);
358
359     /*
360      * wait for Consensus thread to complete
361      */
362     do
363     {
364       try
365       {
366         Thread.sleep(50);
367       } catch (InterruptedException x)
368       {
369       }
370     } while (af.getViewport().getCalcManager().isWorking());
371   }
372
373   @Test(groups = "Functional")
374   public void testClear_HighlightAndSelection()
375   {
376     AlignViewport av = af.getViewport();
377     SearchResultsI highlight = new SearchResults();
378     highlight.addResult(
379             av.getAlignment().getSequenceAt(1).getDatasetSequence(), 50,
380             80);
381     af.alignPanel.highlightSearchResults(highlight);
382     af.avc.markHighlightedColumns(false, false, false);
383     assertNotNull(av.getSearchResults(),
384             "No highlight was created on alignment");
385     assertFalse(av.getColumnSelection().isEmpty(),
386             "No selection was created from highlight");
387     af.deselectAllSequenceMenuItem_actionPerformed(null);
388     assertTrue(av.getColumnSelection().isEmpty(),
389             "No Selection should be present after deselecting all.");
390     assertNull(av.getSearchResults(),
391             "No higlighted search results should be present after deselecting all.");
392   }
393 }