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