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;
24 import static org.testng.Assert.assertNull;
25 import static org.testng.Assert.assertTrue;
27 import java.awt.EventQueue;
28 import java.awt.FontMetrics;
29 import java.awt.event.MouseEvent;
30 import java.lang.reflect.InvocationTargetException;
32 import javax.swing.JLabel;
34 import org.testng.annotations.AfterMethod;
35 import org.testng.annotations.BeforeClass;
36 import org.testng.annotations.Test;
38 import jalview.api.AlignViewportI;
39 import jalview.bin.Cache;
40 import jalview.bin.Jalview;
41 import jalview.commands.EditCommand;
42 import jalview.commands.EditCommand.Action;
43 import jalview.commands.EditCommand.Edit;
44 import jalview.datamodel.Alignment;
45 import jalview.datamodel.AlignmentAnnotation;
46 import jalview.datamodel.AlignmentI;
47 import jalview.datamodel.SearchResults;
48 import jalview.datamodel.SearchResultsI;
49 import jalview.datamodel.Sequence;
50 import jalview.datamodel.SequenceI;
51 import jalview.gui.SeqPanel.MousePos;
52 import jalview.io.DataSourceType;
53 import jalview.io.FileLoader;
54 import jalview.util.MessageManager;
55 import jalview.viewmodel.ViewportRanges;
56 import junit.extensions.PA;
58 public class SeqPanelTest
62 @BeforeClass(alwaysRun = true)
63 public void setUpJvOptionPane()
65 JvOptionPane.setInteractiveMode(false);
66 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
68 @Test(groups = "Functional")
69 public void testSetStatusReturnsNearestResiduePosition()
71 SequenceI seq1 = new Sequence("Seq1", "AACDE");
72 SequenceI seq2 = new Sequence("Seq2", "AA--E");
73 AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
74 AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
76 AlignmentI visAl = alignFrame.getViewport().getAlignment();
78 // Test either side of gap
80 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
81 visAl.getSequenceAt(1), 1, 1), 2);
82 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
83 "Sequence 2 ID: Seq2 Residue: ALA (2)");
85 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
86 visAl.getSequenceAt(1), 4, 1), 3);
87 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
88 "Sequence 2 ID: Seq2 Residue: GLU (3)");
89 // no status message at a gap, returns next residue position to the right
91 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
92 visAl.getSequenceAt(1), 2, 1), 3);
93 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
94 "Sequence 2 ID: Seq2");
96 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
97 visAl.getSequenceAt(1), 3, 1), 3);
98 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
99 "Sequence 2 ID: Seq2");
102 @Test(groups = "Functional")
103 public void testAmbiguousAminoAcidGetsStatusMessage()
105 SequenceI seq1 = new Sequence("Seq1", "ABCDE");
106 SequenceI seq2 = new Sequence("Seq2", "AB--E");
107 AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
108 AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
110 AlignmentI visAl = alignFrame.getViewport().getAlignment();
113 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
114 visAl.getSequenceAt(1), 1, 1), 2);
115 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
116 "Sequence 2 ID: Seq2 Residue: B (2)");
119 @Test(groups = "Functional")
120 public void testGetEditStatusMessage()
122 assertNull(SeqPanel.getEditStatusMessage(null));
124 EditCommand edit = new EditCommand(); // empty
125 assertNull(SeqPanel.getEditStatusMessage(edit));
127 SequenceI[] seqs = new SequenceI[] { new Sequence("a", "b") };
130 edit.addEdit(edit.new Edit(Action.INSERT_GAP, seqs, 1, 1, '-'));
131 String expected = MessageManager.formatMessage("label.insert_gap", "1");
132 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
134 // 3 more gaps makes +4
135 edit.addEdit(edit.new Edit(Action.INSERT_GAP, seqs, 1, 3, '-'));
136 expected = MessageManager.formatMessage("label.insert_gaps", "4");
137 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
139 // 2 deletes makes + 2
140 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-'));
141 expected = MessageManager.formatMessage("label.insert_gaps", "2");
142 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
144 // 2 more deletes makes 0 - no text
145 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-'));
146 assertNull(SeqPanel.getEditStatusMessage(edit));
148 // 1 more delete makes 1 delete
149 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-'));
150 expected = MessageManager.formatMessage("label.delete_gap", "1");
151 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
153 // 1 more delete makes 2 deletes
154 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-'));
155 expected = MessageManager.formatMessage("label.delete_gaps", "2");
156 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
160 * Tests that simulate 'locked editing', where an inserted gap is balanced by
161 * a gap deletion in the selection group, and vice versa
163 @Test(groups = "Functional")
164 public void testGetEditStatusMessage_lockedEditing()
166 EditCommand edit = new EditCommand(); // empty
167 SequenceI[] seqs = new SequenceI[] { new Sequence("a", "b") };
169 // 1 gap inserted, balanced by 1 delete
170 Edit e1 = edit.new Edit(Action.INSERT_GAP, seqs, 1, 1, '-');
172 Edit e2 = edit.new Edit(Action.DELETE_GAP, seqs, 5, 1, '-');
173 e2.setSystemGenerated(true);
175 String expected = MessageManager.formatMessage("label.insert_gap", "1");
176 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
178 // 2 more gaps makes +3
179 Edit e3 = edit.new Edit(Action.INSERT_GAP, seqs, 1, 2, '-');
181 Edit e4 = edit.new Edit(Action.DELETE_GAP, seqs, 5, 2, '-');
182 e4.setSystemGenerated(true);
184 expected = MessageManager.formatMessage("label.insert_gaps", "3");
185 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
187 // 2 deletes makes + 1
188 Edit e5 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-');
190 Edit e6 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 2, '-');
191 e6.setSystemGenerated(true);
193 expected = MessageManager.formatMessage("label.insert_gap", "1");
194 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
196 // 1 more delete makes 0 - no text
197 Edit e7 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-');
199 Edit e8 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 1, '-');
200 e8.setSystemGenerated(true);
202 expected = MessageManager.formatMessage("label.insert_gaps", "2");
203 assertNull(SeqPanel.getEditStatusMessage(edit));
205 // 1 more delete makes 1 delete
206 Edit e9 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-');
208 Edit e10 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 1, '-');
209 e10.setSystemGenerated(true);
211 expected = MessageManager.formatMessage("label.delete_gap", "1");
212 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
214 // 2 more deletes makes 3 deletes
215 Edit e11 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-');
217 Edit e12 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 2, '-');
218 e12.setSystemGenerated(true);
220 expected = MessageManager.formatMessage("label.delete_gaps", "3");
221 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
224 public void testFindMousePosition_unwrapped()
226 String seqData = ">Seq1\nAACDE\n>Seq2\nAA--E\n";
227 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(seqData,
228 DataSourceType.PASTE);
229 AlignViewportI av = alignFrame.getViewport();
230 av.setShowAnnotation(true);
231 av.setWrapAlignment(false);
232 final int charHeight = av.getCharHeight();
233 final int charWidth = av.getCharWidth();
235 assertTrue(charHeight > 0);
236 assertTrue(charWidth > 0);
237 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
239 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
244 * mouse at top left of unwrapped panel
246 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
248 MousePos pos = testee.findMousePosition(evt);
249 assertEquals(pos.column, 0);
250 assertEquals(pos.seqIndex, 0);
251 assertEquals(pos.annotationIndex, -1);
254 @AfterMethod(alwaysRun = true)
255 public void tearDown()
257 Desktop.instance.closeAll_actionPerformed(null);
260 @Test(groups = "Functional")
261 public void testFindMousePosition_wrapped_annotations()
263 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
264 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
265 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
266 "examples/uniref50.fa", DataSourceType.FILE);
267 AlignViewportI av = alignFrame.getViewport();
268 av.setScaleAboveWrapped(false);
269 av.setScaleLeftWrapped(false);
270 av.setScaleRightWrapped(false);
272 alignFrame.alignPanel.updateLayout();
274 final int charHeight = av.getCharHeight();
275 final int charWidth = av.getCharWidth();
276 final int alignmentHeight = av.getAlignment().getHeight();
279 assertTrue(charHeight > 0);
280 assertTrue(charWidth > 0);
281 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
283 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
288 * mouse at top left of wrapped panel; there is a gap of charHeight
289 * above the alignment
291 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
293 MousePos pos = testee.findMousePosition(evt);
294 assertEquals(pos.column, 0);
295 assertEquals(pos.seqIndex, -1); // above sequences
296 assertEquals(pos.annotationIndex, -1);
299 * cursor at bottom of gap above
302 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
304 pos = testee.findMousePosition(evt);
305 assertEquals(pos.seqIndex, -1);
306 assertEquals(pos.annotationIndex, -1);
309 * cursor over top of first sequence
312 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
314 pos = testee.findMousePosition(evt);
315 assertEquals(pos.seqIndex, 0);
316 assertEquals(pos.annotationIndex, -1);
319 * cursor at bottom of first sequence
321 y = 2 * charHeight - 1;
322 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
324 pos = testee.findMousePosition(evt);
325 assertEquals(pos.seqIndex, 0);
326 assertEquals(pos.annotationIndex, -1);
329 * cursor at top of second sequence
332 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
334 pos = testee.findMousePosition(evt);
335 assertEquals(pos.seqIndex, 1);
336 assertEquals(pos.annotationIndex, -1);
339 * cursor at bottom of second sequence
341 y = 3 * charHeight - 1;
342 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
344 pos = testee.findMousePosition(evt);
345 assertEquals(pos.seqIndex, 1);
346 assertEquals(pos.annotationIndex, -1);
349 * cursor at bottom of last sequence
351 y = charHeight * (1 + alignmentHeight) - 1;
352 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
354 pos = testee.findMousePosition(evt);
355 assertEquals(pos.seqIndex, alignmentHeight - 1);
356 assertEquals(pos.annotationIndex, -1);
359 * cursor below sequences, in 3-pixel gap above annotations
360 * method reports index of nearest sequence above
363 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
365 pos = testee.findMousePosition(evt);
366 assertEquals(pos.seqIndex, alignmentHeight - 1);
367 assertEquals(pos.annotationIndex, -1);
370 * cursor still in the gap above annotations, now at the bottom of it
372 y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
373 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
375 pos = testee.findMousePosition(evt);
376 assertEquals(pos.seqIndex, alignmentHeight - 1);
377 assertEquals(pos.annotationIndex, -1);
379 AlignmentAnnotation[] annotationRows = av.getAlignment()
380 .getAlignmentAnnotation();
381 for (int n = 0; n < annotationRows.length; n++)
384 * cursor at the top of the n'th annotation
387 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
389 pos = testee.findMousePosition(evt);
390 assertEquals(pos.seqIndex, alignmentHeight - 1);
391 assertEquals(pos.annotationIndex, n); // over n'th annotation
394 * cursor at the bottom of the n'th annotation
396 y += annotationRows[n].height - 1;
397 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
399 pos = testee.findMousePosition(evt);
400 assertEquals(pos.seqIndex, alignmentHeight - 1);
401 assertEquals(pos.annotationIndex, n);
405 * cursor in gap between wrapped widths
408 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
410 pos = testee.findMousePosition(evt);
411 assertEquals(pos.seqIndex, -1);
412 assertEquals(pos.annotationIndex, -1);
415 * cursor at bottom of gap between wrapped widths
418 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
420 pos = testee.findMousePosition(evt);
421 assertEquals(pos.seqIndex, -1);
422 assertEquals(pos.annotationIndex, -1);
425 * cursor at top of first sequence, second wrapped width
428 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
430 pos = testee.findMousePosition(evt);
431 assertEquals(pos.seqIndex, 0);
432 assertEquals(pos.annotationIndex, -1);
435 @Test(groups = "Functional")
436 public void testFindMousePosition_wrapped_scaleAbove()
438 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
439 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
440 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
441 "examples/uniref50.fa", DataSourceType.FILE);
442 AlignViewportI av = alignFrame.getViewport();
443 av.setScaleAboveWrapped(true);
444 av.setScaleLeftWrapped(false);
445 av.setScaleRightWrapped(false);
446 alignFrame.alignPanel.updateLayout();
448 final int charHeight = av.getCharHeight();
449 final int charWidth = av.getCharWidth();
450 final int alignmentHeight = av.getAlignment().getHeight();
453 assertTrue(charHeight > 0);
454 assertTrue(charWidth > 0);
455 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
457 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
462 * mouse at top left of wrapped panel; there is a gap of charHeight
463 * above the alignment
465 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
467 MousePos pos = testee.findMousePosition(evt);
468 assertEquals(pos.column, 0);
469 assertEquals(pos.seqIndex, -1); // above sequences
470 assertEquals(pos.annotationIndex, -1);
473 * cursor at bottom of gap above
474 * two charHeights including scale panel
476 y = 2 * charHeight - 1;
477 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
479 pos = testee.findMousePosition(evt);
480 assertEquals(pos.seqIndex, -1);
481 assertEquals(pos.annotationIndex, -1);
484 * cursor over top of first sequence
487 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
489 pos = testee.findMousePosition(evt);
490 assertEquals(pos.seqIndex, 0);
491 assertEquals(pos.annotationIndex, -1);
494 * cursor at bottom of first sequence
497 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
499 pos = testee.findMousePosition(evt);
500 assertEquals(pos.seqIndex, 0);
501 assertEquals(pos.annotationIndex, -1);
504 * cursor at top of second sequence
507 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
509 pos = testee.findMousePosition(evt);
510 assertEquals(pos.seqIndex, 1);
511 assertEquals(pos.annotationIndex, -1);
514 * cursor at bottom of second sequence
517 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
519 pos = testee.findMousePosition(evt);
520 assertEquals(pos.seqIndex, 1);
521 assertEquals(pos.annotationIndex, -1);
524 * cursor at bottom of last sequence
525 * (scale + gap + sequences)
527 y = charHeight * (2 + alignmentHeight) - 1;
528 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
530 pos = testee.findMousePosition(evt);
531 assertEquals(pos.seqIndex, alignmentHeight - 1);
532 assertEquals(pos.annotationIndex, -1);
535 * cursor below sequences, in 3-pixel gap above annotations
538 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
540 pos = testee.findMousePosition(evt);
541 assertEquals(pos.seqIndex, alignmentHeight - 1);
542 assertEquals(pos.annotationIndex, -1);
545 * cursor still in the gap above annotations, now at the bottom of it
546 * method reports index of nearest sequence above
548 y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
549 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
551 pos = testee.findMousePosition(evt);
552 assertEquals(pos.seqIndex, alignmentHeight - 1);
553 assertEquals(pos.annotationIndex, -1);
555 AlignmentAnnotation[] annotationRows = av.getAlignment().getAlignmentAnnotation();
556 for (int n = 0; n < annotationRows.length; n++)
559 * cursor at the top of the n'th annotation
562 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
564 pos = testee.findMousePosition(evt);
565 assertEquals(pos.seqIndex, alignmentHeight - 1);
566 assertEquals(pos.annotationIndex, n); // over n'th annotation
569 * cursor at the bottom of the n'th annotation
571 y += annotationRows[n].height - 1;
572 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
574 pos = testee.findMousePosition(evt);
575 SeqCanvas sc = testee.seqCanvas;
576 assertEquals(pos.seqIndex, alignmentHeight - 1,
577 String.format("%s n=%d y=%d %d, %d, %d, %d",
578 annotationRows[n].label, n, y, sc.getWidth(),
579 sc.getHeight(), sc.wrappedRepeatHeightPx,
580 sc.wrappedSpaceAboveAlignment));
581 assertEquals(pos.annotationIndex, n);
585 * cursor in gap between wrapped widths
588 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
590 pos = testee.findMousePosition(evt);
591 assertEquals(pos.seqIndex, -1);
592 assertEquals(pos.annotationIndex, -1);
595 * cursor at bottom of gap between wrapped widths
598 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
600 pos = testee.findMousePosition(evt);
601 assertEquals(pos.seqIndex, -1);
602 assertEquals(pos.annotationIndex, -1);
605 * cursor at top of scale, second wrapped width
608 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
610 pos = testee.findMousePosition(evt);
611 assertEquals(pos.seqIndex, -1);
612 assertEquals(pos.annotationIndex, -1);
615 * cursor at bottom of scale, second wrapped width
618 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
620 pos = testee.findMousePosition(evt);
621 assertEquals(pos.seqIndex, -1);
622 assertEquals(pos.annotationIndex, -1);
625 * cursor at top of first sequence, second wrapped width
628 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
630 pos = testee.findMousePosition(evt);
631 assertEquals(pos.seqIndex, 0);
632 assertEquals(pos.annotationIndex, -1);
635 @Test(groups = "Functional")
636 public void testFindMousePosition_wrapped_noAnnotations()
638 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false");
639 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
640 Cache.applicationProperties.setProperty("FONT_SIZE", "10");
641 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
642 "examples/uniref50.fa", DataSourceType.FILE);
643 AlignViewportI av = alignFrame.getViewport();
644 av.setScaleAboveWrapped(false);
645 av.setScaleLeftWrapped(false);
646 av.setScaleRightWrapped(false);
647 alignFrame.alignPanel.updateLayout();
649 final int charHeight = av.getCharHeight();
650 final int charWidth = av.getCharWidth();
651 final int alignmentHeight = av.getAlignment().getHeight();
654 assertTrue(charHeight > 0);
655 assertTrue(charWidth > 0);
656 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
658 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
663 * mouse at top left of wrapped panel; there is a gap of charHeight
664 * above the alignment
666 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
668 MousePos pos = testee.findMousePosition(evt);
669 assertEquals(pos.column, 0);
670 assertEquals(pos.seqIndex, -1); // above sequences
671 assertEquals(pos.annotationIndex, -1);
674 * cursor over top of first sequence
677 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
679 pos = testee.findMousePosition(evt);
680 assertEquals(pos.seqIndex, 0);
681 assertEquals(pos.annotationIndex, -1);
684 * cursor at bottom of last sequence
686 y = charHeight * (1 + alignmentHeight) - 1;
687 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
689 pos = testee.findMousePosition(evt);
690 assertEquals(pos.seqIndex, alignmentHeight - 1);
691 assertEquals(pos.annotationIndex, -1);
694 * cursor below sequences, at top of charHeight gap between widths
697 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
699 pos = testee.findMousePosition(evt);
700 assertEquals(pos.seqIndex, -1);
701 assertEquals(pos.annotationIndex, -1);
704 * cursor below sequences, at top of charHeight gap between widths
707 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
709 pos = testee.findMousePosition(evt);
710 assertEquals(pos.seqIndex, -1);
711 assertEquals(pos.annotationIndex, -1);
714 * cursor at the top of the first sequence, second width
717 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
719 pos = testee.findMousePosition(evt);
720 assertEquals(pos.seqIndex, 0);
721 assertEquals(pos.annotationIndex, -1);
724 @Test(groups = "Functional")
725 public void testFindColumn_unwrapped()
727 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "false");
728 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
729 "examples/uniref50.fa", DataSourceType.FILE);
730 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
732 final int charWidth = alignFrame.getViewport().getCharWidth();
733 assertTrue(charWidth > 0); // sanity check
734 ViewportRanges ranges = alignFrame.getViewport().getRanges();
735 assertEquals(ranges.getStartRes(), 0);
738 * mouse at top left of unwrapped panel
740 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
742 assertEquals(testee.findColumn(evt), 0);
745 * not quite one charWidth across
748 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
750 assertEquals(testee.findColumn(evt), 0);
753 * one charWidth across
756 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
758 assertEquals(testee.findColumn(evt), 1);
761 * two charWidths across
764 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
766 assertEquals(testee.findColumn(evt), 2);
769 * limited to last column of seqcanvas
772 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
774 SeqCanvas seqCanvas = alignFrame.alignPanel.getSeqPanel().seqCanvas;
775 int w = seqCanvas.getWidth();
776 // limited to number of whole columns, base 0,
777 // and to end of visible range
778 int expected = w / charWidth;
779 expected = Math.min(expected, ranges.getEndRes());
780 assertEquals(testee.findColumn(evt), expected);
783 * hide columns 5-10 (base 1)
785 alignFrame.getViewport().hideColumns(4, 9);
786 x = 5 * charWidth + 2;
787 // x is in 6th visible column, absolute column 12, or 11 base 0
788 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
790 assertEquals(testee.findColumn(evt), 11);
793 @Test(groups = "Functional")
794 public void testFindColumn_wrapped()
796 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
797 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
798 "examples/uniref50.fa", DataSourceType.FILE);
799 AlignViewport av = alignFrame.getViewport();
800 av.setScaleAboveWrapped(false);
801 av.setScaleLeftWrapped(false);
802 av.setScaleRightWrapped(false);
803 alignFrame.alignPanel.updateLayout();
804 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
806 final int charWidth = av.getCharWidth();
807 assertTrue(charWidth > 0); // sanity check
808 assertEquals(av.getRanges().getStartRes(), 0);
811 * mouse at top left of wrapped panel, no West (left) scale
813 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
815 assertEquals(testee.findColumn(evt), 0);
818 * not quite one charWidth across
821 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
823 assertEquals(testee.findColumn(evt), 0);
826 * one charWidth across
829 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
831 assertEquals(testee.findColumn(evt), 1);
834 * x over scale left (before drawn columns) results in -1
836 av.setScaleLeftWrapped(true);
837 alignFrame.alignPanel.updateLayout();
838 SeqCanvas seqCanvas = testee.seqCanvas;
839 int labelWidth = (int) PA.getValue(seqCanvas, "labelWidthWest");
840 assertTrue(labelWidth > 0);
842 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
844 assertEquals(testee.findColumn(evt), -1);
847 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
849 assertEquals(testee.findColumn(evt), 0);
852 * x over right edge of last residue (including scale left)
854 int residuesWide = av.getRanges().getViewportWidth();
855 assertTrue(residuesWide > 0);
856 x = labelWidth + charWidth * residuesWide - 1;
857 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
859 assertEquals(testee.findColumn(evt), residuesWide - 1);
862 * x over scale right (beyond drawn columns) results in -1
864 av.setScaleRightWrapped(true);
865 alignFrame.alignPanel.updateLayout();
866 labelWidth = (int) PA.getValue(seqCanvas, "labelWidthEast");
867 assertTrue(labelWidth > 0);
868 int residuesWide2 = av.getRanges().getViewportWidth();
869 assertTrue(residuesWide2 > 0);
870 assertTrue(residuesWide2 < residuesWide); // available width reduced
871 x += 1; // just over left edge of scale right
872 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
874 assertEquals(testee.findColumn(evt), -1);
876 // todo add startRes offset, hidden columns
879 @BeforeClass(alwaysRun = true)
880 public static void setUpBeforeClass() throws Exception
883 * use read-only test properties file
885 Cache.loadProperties("test/jalview/io/testProps.jvprops");
886 Jalview.main(new String[] { "-nonews" });
890 * waits for Swing event dispatch queue to empty
892 synchronized void waitForSwing()
896 EventQueue.invokeAndWait(new Runnable()
903 } catch (InterruptedException | InvocationTargetException e)
908 @Test(groups = "Functional")
909 public void testFindMousePosition_wrapped_scales_longSequence()
911 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false");
912 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
913 Cache.applicationProperties.setProperty("FONT_SIZE", "14");
914 Cache.applicationProperties.setProperty("FONT_NAME", "SansSerif");
915 Cache.applicationProperties.setProperty("FONT_STYLE", "0");
916 // sequence of 50 bases, doubled 10 times, = 51200 bases
917 String dna = "ATGGCCATTGGGCCCAAATTTCCCAAAGGGTTTCCCTGAGGTCAGTCAGA";
918 for (int i = 0 ; i < 10 ; i++)
922 assertEquals(dna.length(), 51200);
923 AlignFrame alignFrame = new FileLoader()
924 .LoadFileWaitTillLoaded(dna, DataSourceType.PASTE);
925 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
926 AlignViewport av = alignFrame.getViewport();
927 av.setScaleAboveWrapped(true);
928 av.setScaleLeftWrapped(true);
929 av.setScaleRightWrapped(true);
930 alignFrame.alignPanel.updateLayout();
935 } catch (InterruptedException e)
939 final int charHeight = av.getCharHeight();
940 final int charWidth = av.getCharWidth();
941 assertEquals(charHeight, 17);
942 assertEquals(charWidth, 12);
944 FontMetrics fm = testee.getFontMetrics(av.getFont());
945 int labelWidth = fm.stringWidth("00000") + charWidth;
946 assertEquals(labelWidth, 57); // 5 x 9 + charWidth
947 assertEquals(testee.seqCanvas.getLabelWidthWest(), labelWidth);
953 * mouse at top left of wrapped panel; there is a gap of 2 * charHeight
954 * above the alignment
956 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
958 MousePos pos = testee.findMousePosition(evt);
959 assertEquals(pos.column, -1); // over scale left, not an alignment column
960 assertEquals(pos.seqIndex, -1); // above sequences
961 assertEquals(pos.annotationIndex, -1);
964 * cursor over scale above first sequence
968 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
970 pos = testee.findMousePosition(evt);
971 assertEquals(pos.seqIndex, -1);
972 assertEquals(pos.column, 0);
973 assertEquals(pos.annotationIndex, -1);
976 * cursor over scale left of first sequence
980 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
982 pos = testee.findMousePosition(evt);
983 assertEquals(pos.seqIndex, 0);
984 assertEquals(pos.column, -1);
985 assertEquals(pos.annotationIndex, -1);
988 * cursor over start of first sequence
991 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
993 pos = testee.findMousePosition(evt);
994 assertEquals(pos.seqIndex, 0);
995 assertEquals(pos.column, 0);
996 assertEquals(pos.annotationIndex, -1);
999 * move one character right, to bottom pixel of same row
1002 y += charHeight - 1;
1003 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1005 pos = testee.findMousePosition(evt);
1006 assertEquals(pos.seqIndex, 0);
1007 assertEquals(pos.column, 1);
1010 * move down one pixel - now in the no man's land between rows
1013 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1015 pos = testee.findMousePosition(evt);
1016 assertEquals(pos.seqIndex, -1);
1017 assertEquals(pos.column, 1);
1020 * move down two char heights less one pixel - still in the no man's land
1021 * (scale above + spacer line)
1023 y += (2 * charHeight - 1);
1024 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1026 pos = testee.findMousePosition(evt);
1027 assertEquals(pos.seqIndex, -1);
1028 assertEquals(pos.column, 1);
1031 * move down one more pixel - now on the next row of the sequence
1034 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1036 pos = testee.findMousePosition(evt);
1037 assertEquals(pos.seqIndex, 0);
1038 assertEquals(pos.column, 1 + av.getWrappedWidth());
1041 * scroll to near the end of the sequence
1043 SearchResultsI sr = new SearchResults();
1044 int scrollTo = dna.length() - 1000;
1045 sr.addResult(av.getAlignment().getSequenceAt(0), scrollTo, scrollTo);
1046 alignFrame.alignPanel.scrollToPosition(sr);
1049 * place the mouse on the first column of the 6th sequence, and
1050 * verify that (computed) findMousePosition matches (actual) ViewportRanges
1053 y = 17 * charHeight; // 17 = 6 times two header rows and 5 sequence rows
1054 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1056 pos = testee.findMousePosition(evt);
1057 assertEquals(pos.seqIndex, 0);
1058 int expected = av.getRanges().getStartRes() + 5 * av.getWrappedWidth();
1059 assertEquals(pos.column, expected);