2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import static org.testng.Assert.assertEquals;
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;
32 import java.awt.FontMetrics;
34 import org.testng.Assert;
35 import org.testng.annotations.BeforeClass;
36 import org.testng.annotations.Test;
38 import junit.extensions.PA;
40 public class SeqCanvasTest
42 @BeforeClass(alwaysRun = true)
46 Jalview.setSynchronous(true);
50 * Test the method that computes wrapped width in residues, height of wrapped
51 * widths in pixels, and the number of widths visible
53 @Test(groups = "Functional")
54 public void testCalculateWrappedGeometry_noAnnotations()
56 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
57 "examples/uniref50.fa", DataSourceType.FILE);
58 AlignViewport av = af.getViewport();
59 AlignmentI al = av.getAlignment();
60 assertEquals(al.getWidth(), 157);
61 assertEquals(al.getHeight(), 15);
62 av.getRanges().setStartEndSeq(0, 14);
64 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
66 av.setWrapAlignment(true);
67 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
68 int charHeight = av.getCharHeight();
69 int charWidth = av.getCharWidth();
70 Assert.assertTrue(charHeight == 17 && charWidth == 12
71 || charHeight == 19 && charWidth == 11,
72 "char height/width " + charHeight + "/" + charWidth);
74 // assertEquals(charHeight, Platform.isMac() ? 17 : 19);
75 // assertEquals(charWidth, Platform.isMac() ? 12 : 11);
78 * first with scales above, left, right
80 av.setShowAnnotation(false);
81 av.setScaleAboveWrapped(true);
82 av.setScaleLeftWrapped(true);
83 av.setScaleRightWrapped(true);
84 FontMetrics fm = testee.getFontMetrics(av.getFont());
85 int labelWidth = fm.stringWidth("000") + charWidth;
86 // BH 2020.03.22 It is not really necessary to be this detailed. Different
88 // always have slightly different parameters. StringgWidths are not
89 // necessarily linear sums of the letters involved.
90 // for example, the calculation for JavaScript is a float that has to be
92 // ..............................mac................PC................linux?
94 labelWidth == 39 || labelWidth == 35 || labelWidth == 36);// 3 * 9 +
106 * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
107 * take the whole multiple of character widths
109 int canvasWidth = 400;
110 int canvasHeight = 300;
111 int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
112 int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
113 assertEquals(wrappedWidth, residueColumns);
114 assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
115 assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
116 assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
118 int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
119 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
120 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
123 * repeat height is 17 * (2 + 15) = 289
124 * make canvas height 2 * 289 + 3 * charHeight so just enough to
125 * draw 2 widths and the first sequence of a third
127 canvasHeight = charHeight * (17 * 2 + 3);
128 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
129 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
132 * reduce canvas height by 1 pixel
133 * - should not be enough height to draw 3 widths
136 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
137 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
140 * turn off scale above - can now fit in 2 and a bit widths
142 av.setScaleAboveWrapped(false);
143 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
144 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
147 * reduce height to enough for 2 widths and not quite a third
148 * i.e. two repeating heights + spacer + sequence - 1 pixel
150 canvasHeight = charHeight * (16 * 2 + 2) - 1;
151 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
152 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
155 * make canvas width enough for scales and 20 residues
157 canvasWidth = 2 * labelWidth + 20 * charWidth;
158 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
160 assertEquals(wrappedWidth, 20);
163 * reduce width by 1 pixel - rounds down to 19 residues
166 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
168 assertEquals(wrappedWidth, 19);
171 * turn off West scale - adds labelWidth (39) to available for residues
172 * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
174 av.setScaleLeftWrapped(false);
175 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
177 assertEquals(wrappedWidth, 23);
180 * add 10 pixels to width to fit in another whole residue column
183 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
185 assertEquals(wrappedWidth, 23);
187 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
189 assertEquals(wrappedWidth, 24);
192 * turn off East scale to gain 39 more pixels (3 columns remainder 3)
194 av.setScaleRightWrapped(false);
195 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
197 assertEquals(wrappedWidth, 27);
200 * add 9 pixels to width to gain a residue column
203 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
205 assertEquals(wrappedWidth, 27); // 8px not enough
207 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
209 assertEquals(wrappedWidth, 28); // 9px is enough
212 * now West but not East scale - lose 39 pixels or 4 columns
214 av.setScaleLeftWrapped(true);
215 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
217 assertEquals(wrappedWidth, 24);
220 * adding 3 pixels to width regains one column
223 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
225 Assert.assertTrue(wrappedWidth == 24 || wrappedWidth == 25,
226 "WrappedWidth [" + wrappedWidth + "] should be 24 or 25"); // 2px
230 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
232 assertEquals(wrappedWidth, 25); // 3px is enough
235 * turn off scales left and right, make width exactly 157 columns
237 av.setScaleLeftWrapped(false);
238 canvasWidth = al.getWidth() * charWidth;
239 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
240 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
244 * Test the method that computes wrapped width in residues, height of wrapped
245 * widths in pixels, and the number of widths visible
247 @Test(groups = "Functional")
248 public void testCalculateWrappedGeometry_withAnnotations()
250 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
251 "examples/uniref50.fa", DataSourceType.FILE);
252 AlignViewport av = af.getViewport();
253 AlignmentI al = av.getAlignment();
254 assertEquals(al.getWidth(), 157);
255 assertEquals(al.getHeight(), 15);
257 av.setWrapAlignment(true);
258 av.getRanges().setStartEndSeq(0, 14);
259 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
260 int charHeight = av.getCharHeight();
261 int charWidth = av.getCharWidth();
264 charHeight == 17 && charWidth == 12
265 || charHeight == 19 && charWidth == 11,
266 "char height/width " + charHeight + "/" + charWidth);
267 // assertEquals(charHeight, Platform.isMac() ? 17 : 19);
268 // assertEquals(charWidth, Platform.isMac() ? 12 : 11);
270 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
273 * first with scales above, left, right
275 av.setShowAnnotation(true);
276 av.setScaleAboveWrapped(true);
277 av.setScaleLeftWrapped(true);
278 av.setScaleRightWrapped(true);
280 FontMetrics fm = testee.getFontMetrics(av.getFont());
281 int labelWidth = fm.stringWidth("000") + charWidth;
282 // BH 2020.03.22 It is not really necessary to be this detailed. Different
284 // always have slightly different parameters. StringgWidths are not
285 // necessarily linear sums of the letters involved.
286 // for example, the calculation for JavaScript is a float that has to be
288 // ..............................mac................PC................linux?
290 labelWidth == 39 || labelWidth == 35 || labelWidth == 36);// 3 * 9 +
300 // int labelWidth = fm.stringWidth("000") + charWidth;
301 // assertEquals(labelWidth,
302 // Platform.isMac() ? 3 * 9 + charWidth : 3 * 8 + charWidth);
304 int annotationHeight = testee.getAnnotationHeight();
307 * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
308 * take the whole multiple of character widths
310 int canvasWidth = 400;
311 int canvasHeight = 300;
312 int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
313 int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
314 assertEquals(wrappedWidth, residueColumns);
315 assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
316 assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
317 assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
319 int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
320 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
321 + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight);
322 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
325 * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510
326 * make canvas height 2 of these plus 3 charHeights
327 * so just enough to draw 2 widths, gap + scale + the first sequence of a third
329 canvasHeight = charHeight * (17 * 2 + 3)
330 + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP);
331 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
332 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
335 * reduce canvas height by 1 pixel - should not be enough height
339 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
340 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
343 * turn off scale above - can now fit in 2 and a bit widths
345 av.setScaleAboveWrapped(false);
346 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
347 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
350 * reduce height to enough for 2 widths and not quite a third
351 * i.e. two repeating heights + spacer + sequence - 1 pixel
353 canvasHeight = charHeight * (16 * 2 + 2)
354 + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1;
355 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
356 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
359 * add 1 pixel to height - should now get 3 widths drawn
362 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
363 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
367 * Test simulates loading an unwrapped alignment, shrinking it vertically so
368 * not all sequences are visible, then changing to wrapped mode. The ranges
369 * endSeq should be unchanged, but the vertical repeat height should include
372 @Test(groups = "Functional")
373 public void testCalculateWrappedGeometry_fromScrolled()
375 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
376 "examples/uniref50.fa", DataSourceType.FILE);
377 AlignViewport av = af.getViewport();
378 AlignmentI al = av.getAlignment();
379 assertEquals(al.getWidth(), 157);
380 assertEquals(al.getHeight(), 15);
382 av.getRanges().setStartEndSeq(0, 3);
383 av.setShowAnnotation(false);
384 av.setScaleAboveWrapped(true);
385 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
386 av.setWrapAlignment(true);
387 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
388 int charHeight = av.getCharHeight();
389 int charWidth = av.getCharWidth();
390 // Windows h=19, w=11; Mac (and Linux?) 17,11
391 Assert.assertTrue(charHeight == 17 && charWidth == 12
392 || charHeight == 19 && charWidth == 11,
393 "char height/width " + charHeight + "/" + charWidth);
394 int canvasWidth = 400;
395 int canvasHeight = 300;
396 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
397 int repeatingHeight = (int) PA.getValue(testee,
398 "wrappedRepeatHeightPx");
399 assertEquals(av.getRanges().getEndSeq(), 3,
400 "endSeq should be 3"); // unchanged
401 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));