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;
30 import jalview.viewmodel.ViewportRanges;
33 import java.awt.FontMetrics;
35 import org.testng.Assert;
36 import org.testng.annotations.BeforeClass;
37 import org.testng.annotations.Test;
39 import junit.extensions.PA;
41 public class SeqCanvasTest
43 @BeforeClass(alwaysRun = true)
47 Jalview.setSynchronous(true);
51 * Test the method that computes wrapped width in residues, height of wrapped
52 * widths in pixels, and the number of widths visible
54 @Test(groups = "Functional")
55 public void testCalculateWrappedGeometry_noAnnotations()
57 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
58 "examples/uniref50.fa", DataSourceType.FILE);
59 AlignViewport av = af.getViewport();
60 AlignmentI al = av.getAlignment();
61 assertEquals(al.getWidth(), 157);
62 assertEquals(al.getHeight(), 15);
63 av.getRanges().setStartEndSeq(0, 14);
65 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
67 av.setWrapAlignment(true);
68 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
69 int charHeight = av.getCharHeight();
70 int charWidth = av.getCharWidth();
71 Assert.assertTrue(charHeight == 17 && charWidth == 12
72 || charHeight == 19 && charWidth == 11,
73 "char height/width " + charHeight + "/" + charWidth);
75 // assertEquals(charHeight, Platform.isMac() ? 17 : 19);
76 // assertEquals(charWidth, Platform.isMac() ? 12 : 11);
79 * first with scales above, left, right
81 av.setShowAnnotation(false);
82 av.setScaleAboveWrapped(true);
83 av.setScaleLeftWrapped(true);
84 av.setScaleRightWrapped(true);
85 FontMetrics fm = testee.getFontMetrics(av.getFont());
86 int labelWidth = fm.stringWidth("000") + charWidth;
87 // BH 2020.03.22 It is not really necessary to be this detailed. Different
89 // always have slightly different parameters. StringgWidths are not
90 // necessarily linear sums of the letters involved.
91 // for example, the calculation for JavaScript is a float that has to be
93 // ..............................mac................PC................linux?
95 labelWidth == 39 || labelWidth == 35 || labelWidth == 36);// 3 * 9 +
107 * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
108 * take the whole multiple of character widths
110 int canvasWidth = 400;
111 int canvasHeight = 300;
112 int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
113 int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
114 assertEquals(wrappedWidth, residueColumns);
115 assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
116 assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
117 assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
119 int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
120 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));
121 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
124 * repeat height is 17 * (2 + 15) = 289
125 * make canvas height 2 * 289 + 3 * charHeight so just enough to
126 * draw 2 widths and the first sequence of a third
128 canvasHeight = charHeight * (17 * 2 + 3);
129 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
130 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
133 * reduce canvas height by 1 pixel
134 * - should not be enough height to draw 3 widths
137 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
138 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
141 * turn off scale above - can now fit in 2 and a bit widths
143 av.setScaleAboveWrapped(false);
144 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
145 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
148 * reduce height to enough for 2 widths and not quite a third
149 * i.e. two repeating heights + spacer + sequence - 1 pixel
151 canvasHeight = charHeight * (16 * 2 + 2) - 1;
152 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
153 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
156 * make canvas width enough for scales and 20 residues
158 canvasWidth = 2 * labelWidth + 20 * charWidth;
159 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
161 assertEquals(wrappedWidth, 20);
164 * reduce width by 1 pixel - rounds down to 19 residues
167 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
169 assertEquals(wrappedWidth, 19);
172 * turn off West scale - adds labelWidth (39) to available for residues
173 * which with the 11 remainder makes 50 which is 4 more charWidths rem 2
175 av.setScaleLeftWrapped(false);
176 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
178 assertEquals(wrappedWidth, 23);
181 * add 10 pixels to width to fit in another whole residue column
184 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
186 assertEquals(wrappedWidth, 23);
188 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
190 assertEquals(wrappedWidth, 24);
193 * turn off East scale to gain 39 more pixels (3 columns remainder 3)
195 av.setScaleRightWrapped(false);
196 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
198 assertEquals(wrappedWidth, 27);
201 * add 9 pixels to width to gain a residue column
204 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
206 assertEquals(wrappedWidth, 27); // 8px not enough
208 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
210 assertEquals(wrappedWidth, 28); // 9px is enough
213 * now West but not East scale - lose 39 pixels or 4 columns
215 av.setScaleLeftWrapped(true);
216 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
218 assertEquals(wrappedWidth, 24);
221 * adding 3 pixels to width regains one column
224 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
226 Assert.assertTrue(wrappedWidth == 24 || wrappedWidth == 25,
227 "WrappedWidth [" + wrappedWidth + "] should be 24 or 25"); // 2px
231 wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
233 assertEquals(wrappedWidth, 25); // 3px is enough
236 * turn off scales left and right, make width exactly 157 columns
238 av.setScaleLeftWrapped(false);
239 canvasWidth = al.getWidth() * charWidth;
240 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
241 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
245 * Test the method that computes wrapped width in residues, height of wrapped
246 * widths in pixels, and the number of widths visible
248 @Test(groups = "Functional")
249 public void testCalculateWrappedGeometry_withAnnotations()
251 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
252 "examples/uniref50.fa", DataSourceType.FILE);
253 AlignViewport av = af.getViewport();
254 AlignmentI al = av.getAlignment();
255 assertEquals(al.getWidth(), 157);
256 assertEquals(al.getHeight(), 15);
258 av.setWrapAlignment(true);
259 av.getRanges().setStartEndSeq(0, 14);
260 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
261 int charHeight = av.getCharHeight();
262 int charWidth = av.getCharWidth();
265 charHeight == 17 && charWidth == 12
266 || charHeight == 19 && charWidth == 11,
267 "char height/width " + charHeight + "/" + charWidth);
268 // assertEquals(charHeight, Platform.isMac() ? 17 : 19);
269 // assertEquals(charWidth, Platform.isMac() ? 12 : 11);
271 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
274 * first with scales above, left, right
276 av.setShowAnnotation(true);
277 av.setScaleAboveWrapped(true);
278 av.setScaleLeftWrapped(true);
279 av.setScaleRightWrapped(true);
281 FontMetrics fm = testee.getFontMetrics(av.getFont());
282 int labelWidth = fm.stringWidth("000") + charWidth;
283 // BH 2020.03.22 It is not really necessary to be this detailed. Different
285 // always have slightly different parameters. StringgWidths are not
286 // necessarily linear sums of the letters involved.
287 // for example, the calculation for JavaScript is a float that has to be
289 // ..............................mac................PC................linux?
291 labelWidth == 39 || labelWidth == 35 || labelWidth == 36);// 3 * 9 +
301 // int labelWidth = fm.stringWidth("000") + charWidth;
302 // assertEquals(labelWidth,
303 // Platform.isMac() ? 3 * 9 + charWidth : 3 * 8 + charWidth);
305 int annotationHeight = testee.getAnnotationHeight();
308 * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
309 * take the whole multiple of character widths
311 int canvasWidth = 400;
312 int canvasHeight = 300;
313 int residueColumns = (canvasWidth - 2 * labelWidth) / charWidth;
314 int wrappedWidth = testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
315 assertEquals(wrappedWidth, residueColumns);
316 assertEquals(PA.getValue(testee, "labelWidthWest"), labelWidth);
317 assertEquals(PA.getValue(testee, "labelWidthEast"), labelWidth);
318 assertEquals(PA.getValue(testee, "wrappedSpaceAboveAlignment"),
320 int repeatingHeight = (int) PA.getValue(testee, "wrappedRepeatHeightPx");
321 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight())
322 + SeqCanvas.SEQS_ANNOTATION_GAP + annotationHeight);
323 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 1);
326 * repeat height is 17 * (2 + 15) = 289 + 3 + annotationHeight = 510
327 * make canvas height 2 of these plus 3 charHeights
328 * so just enough to draw 2 widths, gap + scale + the first sequence of a third
330 canvasHeight = charHeight * (17 * 2 + 3)
331 + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP);
332 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
333 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
336 * reduce canvas height by 1 pixel - should not be enough height
340 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
341 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
344 * turn off scale above - can now fit in 2 and a bit widths
346 av.setScaleAboveWrapped(false);
347 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
348 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
351 * reduce height to enough for 2 widths and not quite a third
352 * i.e. two repeating heights + spacer + sequence - 1 pixel
354 canvasHeight = charHeight * (16 * 2 + 2)
355 + 2 * (annotationHeight + SeqCanvas.SEQS_ANNOTATION_GAP) - 1;
356 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
357 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 2);
360 * add 1 pixel to height - should now get 3 widths drawn
363 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
364 assertEquals(PA.getValue(testee, "wrappedVisibleWidths"), 3);
368 * Test simulates loading an unwrapped alignment, shrinking it vertically so
369 * not all sequences are visible, then changing to wrapped mode. The ranges
370 * endSeq should be unchanged, but the vertical repeat height should include
373 @Test(groups = "Functional")
374 public void testCalculateWrappedGeometry_fromScrolled()
376 AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
377 "examples/uniref50.fa", DataSourceType.FILE);
378 AlignViewport av = af.getViewport();
379 AlignmentI al = av.getAlignment();
380 assertEquals(al.getWidth(), 157);
381 assertEquals(al.getHeight(), 15);
382 av.getRanges().setStartEndSeq(0, 3);
384 s += " SC1 " + av.getRanges() + " " + ViewportRanges.sTest;
385 av.setShowAnnotation(false);
386 av.setScaleAboveWrapped(true);
387 SeqCanvas testee = af.alignPanel.getSeqPanel().seqCanvas;
388 av.setWrapAlignment(true);
389 av.setFont(new Font("SansSerif", Font.PLAIN, 14), true);
390 int charHeight = av.getCharHeight();
391 int charWidth = av.getCharWidth();
392 // Windows h=19, w=11; Mac (and Linux?) 17,11
393 Assert.assertTrue(charHeight == 17 && charWidth == 12
394 || charHeight == 19 && charWidth == 11,
395 "char height/width " + charHeight + "/" + charWidth);
396 int canvasWidth = 400;
397 int canvasHeight = 300;
398 testee.calculateWrappedGeometry(canvasWidth, canvasHeight);
399 int repeatingHeight = (int) PA.getValue(testee,
400 "wrappedRepeatHeightPx");
401 assertEquals(av.getRanges().getEndSeq(), 0, "endSeq should be 3 " + s); // unchanged
402 assertEquals(repeatingHeight, charHeight * (2 + al.getHeight()));