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;
37 import jalview.api.AlignViewportI;
38 import jalview.bin.Cache;
39 import jalview.bin.Jalview;
40 import jalview.commands.EditCommand;
41 import jalview.commands.EditCommand.Action;
42 import jalview.commands.EditCommand.Edit;
43 import jalview.datamodel.Alignment;
44 import jalview.datamodel.AlignmentAnnotation;
45 import jalview.datamodel.AlignmentI;
46 import jalview.datamodel.SearchResults;
47 import jalview.datamodel.SearchResultsI;
48 import jalview.datamodel.Sequence;
49 import jalview.datamodel.SequenceI;
50 import jalview.gui.SeqPanel.MousePos;
51 import jalview.io.DataSourceType;
52 import jalview.io.FileLoader;
53 import jalview.util.MessageManager;
54 import jalview.viewmodel.ViewportRanges;
57 import junit.extensions.PA;
59 public class SeqPanelTest
63 @BeforeClass(alwaysRun = true)
64 public void setUpJvOptionPane()
66 JvOptionPane.setInteractiveMode(false);
67 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
69 @Test(groups = "Functional")
70 public void testSetStatusReturnsNearestResiduePosition()
72 SequenceI seq1 = new Sequence("Seq1", "AACDE");
73 SequenceI seq2 = new Sequence("Seq2", "AA--E");
74 AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
75 AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
77 AlignmentI visAl = alignFrame.getViewport().getAlignment();
79 // Test either side of gap
81 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
82 visAl.getSequenceAt(1), 1, 1), 2);
83 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
84 "Sequence 2 ID: Seq2 Residue: ALA (2)");
86 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
87 visAl.getSequenceAt(1), 4, 1), 3);
88 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
89 "Sequence 2 ID: Seq2 Residue: GLU (3)");
90 // no status message at a gap, returns next residue position to the right
92 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
93 visAl.getSequenceAt(1), 2, 1), 3);
94 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
95 "Sequence 2 ID: Seq2");
97 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
98 visAl.getSequenceAt(1), 3, 1), 3);
99 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
100 "Sequence 2 ID: Seq2");
103 @Test(groups = "Functional")
104 public void testAmbiguousAminoAcidGetsStatusMessage()
106 SequenceI seq1 = new Sequence("Seq1", "ABCDE");
107 SequenceI seq2 = new Sequence("Seq2", "AB--E");
108 AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
109 AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
111 AlignmentI visAl = alignFrame.getViewport().getAlignment();
114 alignFrame.alignPanel.getSeqPanel().setStatusMessage(
115 visAl.getSequenceAt(1), 1, 1), 2);
116 assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
117 "Sequence 2 ID: Seq2 Residue: B (2)");
120 @Test(groups = "Functional")
121 public void testGetEditStatusMessage()
123 assertNull(SeqPanel.getEditStatusMessage(null));
125 EditCommand edit = new EditCommand(); // empty
126 assertNull(SeqPanel.getEditStatusMessage(edit));
128 SequenceI[] seqs = new SequenceI[] { new Sequence("a", "b") };
131 edit.addEdit(edit.new Edit(Action.INSERT_GAP, seqs, 1, 1, '-'));
132 String expected = MessageManager.formatMessage("label.insert_gap", "1");
133 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
135 // 3 more gaps makes +4
136 edit.addEdit(edit.new Edit(Action.INSERT_GAP, seqs, 1, 3, '-'));
137 expected = MessageManager.formatMessage("label.insert_gaps", "4");
138 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
140 // 2 deletes makes + 2
141 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-'));
142 expected = MessageManager.formatMessage("label.insert_gaps", "2");
143 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
145 // 2 more deletes makes 0 - no text
146 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-'));
147 assertNull(SeqPanel.getEditStatusMessage(edit));
149 // 1 more delete makes 1 delete
150 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-'));
151 expected = MessageManager.formatMessage("label.delete_gap", "1");
152 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
154 // 1 more delete makes 2 deletes
155 edit.addEdit(edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-'));
156 expected = MessageManager.formatMessage("label.delete_gaps", "2");
157 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
161 * Tests that simulate 'locked editing', where an inserted gap is balanced by
162 * a gap deletion in the selection group, and vice versa
164 @Test(groups = "Functional")
165 public void testGetEditStatusMessage_lockedEditing()
167 EditCommand edit = new EditCommand(); // empty
168 SequenceI[] seqs = new SequenceI[] { new Sequence("a", "b") };
170 // 1 gap inserted, balanced by 1 delete
171 Edit e1 = edit.new Edit(Action.INSERT_GAP, seqs, 1, 1, '-');
173 Edit e2 = edit.new Edit(Action.DELETE_GAP, seqs, 5, 1, '-');
174 e2.setSystemGenerated(true);
176 String expected = MessageManager.formatMessage("label.insert_gap", "1");
177 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
179 // 2 more gaps makes +3
180 Edit e3 = edit.new Edit(Action.INSERT_GAP, seqs, 1, 2, '-');
182 Edit e4 = edit.new Edit(Action.DELETE_GAP, seqs, 5, 2, '-');
183 e4.setSystemGenerated(true);
185 expected = MessageManager.formatMessage("label.insert_gaps", "3");
186 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
188 // 2 deletes makes + 1
189 Edit e5 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-');
191 Edit e6 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 2, '-');
192 e6.setSystemGenerated(true);
194 expected = MessageManager.formatMessage("label.insert_gap", "1");
195 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
197 // 1 more delete makes 0 - no text
198 Edit e7 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-');
200 Edit e8 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 1, '-');
201 e8.setSystemGenerated(true);
203 expected = MessageManager.formatMessage("label.insert_gaps", "2");
204 assertNull(SeqPanel.getEditStatusMessage(edit));
206 // 1 more delete makes 1 delete
207 Edit e9 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 1, '-');
209 Edit e10 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 1, '-');
210 e10.setSystemGenerated(true);
212 expected = MessageManager.formatMessage("label.delete_gap", "1");
213 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
215 // 2 more deletes makes 3 deletes
216 Edit e11 = edit.new Edit(Action.DELETE_GAP, seqs, 1, 2, '-');
218 Edit e12 = edit.new Edit(Action.INSERT_GAP, seqs, 5, 2, '-');
219 e12.setSystemGenerated(true);
221 expected = MessageManager.formatMessage("label.delete_gaps", "3");
222 assertEquals(SeqPanel.getEditStatusMessage(edit), expected);
225 public void testFindMousePosition_unwrapped()
227 String seqData = ">Seq1\nAACDE\n>Seq2\nAA--E\n";
228 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(seqData,
229 DataSourceType.PASTE);
230 AlignViewportI av = alignFrame.getViewport();
231 av.setShowAnnotation(true);
232 av.setWrapAlignment(false);
233 final int charHeight = av.getCharHeight();
234 final int charWidth = av.getCharWidth();
236 assertTrue(charHeight > 0);
237 assertTrue(charWidth > 0);
238 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
240 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
245 * mouse at top left of unwrapped panel
247 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
249 MousePos pos = testee.findMousePosition(evt);
250 assertEquals(pos.column, 0);
251 assertEquals(pos.seqIndex, 0);
252 assertEquals(pos.annotationIndex, -1);
255 @AfterMethod(alwaysRun = true)
256 public void tearDown()
258 Desktop.instance.closeAll_actionPerformed(null);
261 @Test(groups = "Functional")
262 public void testFindMousePosition_wrapped_annotations()
264 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
265 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
266 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
267 "examples/uniref50.fa", DataSourceType.FILE);
268 AlignViewportI av = alignFrame.getViewport();
269 av.setScaleAboveWrapped(false);
270 av.setScaleLeftWrapped(false);
271 av.setScaleRightWrapped(false);
273 alignFrame.alignPanel.updateLayout();
275 final int charHeight = av.getCharHeight();
276 final int charWidth = av.getCharWidth();
277 final int alignmentHeight = av.getAlignment().getHeight();
280 assertTrue(charHeight > 0);
281 assertTrue(charWidth > 0);
282 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
284 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
289 * mouse at top left of wrapped panel; there is a gap of charHeight
290 * above the alignment
292 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
294 MousePos pos = testee.findMousePosition(evt);
295 assertEquals(pos.column, 0);
296 assertEquals(pos.seqIndex, -1); // above sequences
297 assertEquals(pos.annotationIndex, -1);
300 * cursor at bottom of gap above
303 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
305 pos = testee.findMousePosition(evt);
306 assertEquals(pos.seqIndex, -1);
307 assertEquals(pos.annotationIndex, -1);
310 * cursor over top of first sequence
313 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
315 pos = testee.findMousePosition(evt);
316 assertEquals(pos.seqIndex, 0);
317 assertEquals(pos.annotationIndex, -1);
320 * cursor at bottom of first sequence
322 y = 2 * charHeight - 1;
323 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
325 pos = testee.findMousePosition(evt);
326 assertEquals(pos.seqIndex, 0);
327 assertEquals(pos.annotationIndex, -1);
330 * cursor at top of second sequence
333 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
335 pos = testee.findMousePosition(evt);
336 assertEquals(pos.seqIndex, 1);
337 assertEquals(pos.annotationIndex, -1);
340 * cursor at bottom of second sequence
342 y = 3 * charHeight - 1;
343 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
345 pos = testee.findMousePosition(evt);
346 assertEquals(pos.seqIndex, 1);
347 assertEquals(pos.annotationIndex, -1);
350 * cursor at bottom of last sequence
352 y = charHeight * (1 + alignmentHeight) - 1;
353 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
355 pos = testee.findMousePosition(evt);
356 assertEquals(pos.seqIndex, alignmentHeight - 1);
357 assertEquals(pos.annotationIndex, -1);
360 * cursor below sequences, in 3-pixel gap above annotations
361 * method reports index of nearest sequence above
364 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
366 pos = testee.findMousePosition(evt);
367 assertEquals(pos.seqIndex, alignmentHeight - 1);
368 assertEquals(pos.annotationIndex, -1);
371 * cursor still in the gap above annotations, now at the bottom of it
373 y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
374 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
376 pos = testee.findMousePosition(evt);
377 assertEquals(pos.seqIndex, alignmentHeight - 1);
378 assertEquals(pos.annotationIndex, -1);
380 AlignmentAnnotation[] annotationRows = av.getAlignment()
381 .getAlignmentAnnotation();
382 for (int n = 0; n < annotationRows.length; n++)
385 * cursor at the top of the n'th annotation
388 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
390 pos = testee.findMousePosition(evt);
391 assertEquals(pos.seqIndex, alignmentHeight - 1);
392 assertEquals(pos.annotationIndex, n); // over n'th annotation
395 * cursor at the bottom of the n'th annotation
397 y += annotationRows[n].height - 1;
398 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
400 pos = testee.findMousePosition(evt);
401 assertEquals(pos.seqIndex, alignmentHeight - 1);
402 assertEquals(pos.annotationIndex, n);
406 * cursor in gap between wrapped widths
409 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
411 pos = testee.findMousePosition(evt);
412 assertEquals(pos.seqIndex, -1);
413 assertEquals(pos.annotationIndex, -1);
416 * cursor at bottom of gap between wrapped widths
419 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
421 pos = testee.findMousePosition(evt);
422 assertEquals(pos.seqIndex, -1);
423 assertEquals(pos.annotationIndex, -1);
426 * cursor at top of first sequence, second wrapped width
429 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
431 pos = testee.findMousePosition(evt);
432 assertEquals(pos.seqIndex, 0);
433 assertEquals(pos.annotationIndex, -1);
436 @Test(groups = "Functional")
437 public void testFindMousePosition_wrapped_scaleAbove()
439 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
440 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
441 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
442 "examples/uniref50.fa", DataSourceType.FILE);
443 AlignViewportI av = alignFrame.getViewport();
444 av.setScaleAboveWrapped(true);
445 av.setScaleLeftWrapped(false);
446 av.setScaleRightWrapped(false);
447 alignFrame.alignPanel.updateLayout();
449 final int charHeight = av.getCharHeight();
450 final int charWidth = av.getCharWidth();
451 final int alignmentHeight = av.getAlignment().getHeight();
454 assertTrue(charHeight > 0);
455 assertTrue(charWidth > 0);
456 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
458 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
463 * mouse at top left of wrapped panel; there is a gap of charHeight
464 * above the alignment
466 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
468 MousePos pos = testee.findMousePosition(evt);
469 assertEquals(pos.column, 0);
470 assertEquals(pos.seqIndex, -1); // above sequences
471 assertEquals(pos.annotationIndex, -1);
474 * cursor at bottom of gap above
475 * two charHeights including scale panel
477 y = 2 * charHeight - 1;
478 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
480 pos = testee.findMousePosition(evt);
481 assertEquals(pos.seqIndex, -1);
482 assertEquals(pos.annotationIndex, -1);
485 * cursor over top of first sequence
488 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
490 pos = testee.findMousePosition(evt);
491 assertEquals(pos.seqIndex, 0);
492 assertEquals(pos.annotationIndex, -1);
495 * cursor at bottom of first sequence
498 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
500 pos = testee.findMousePosition(evt);
501 assertEquals(pos.seqIndex, 0);
502 assertEquals(pos.annotationIndex, -1);
505 * cursor at top of second sequence
508 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
510 pos = testee.findMousePosition(evt);
511 assertEquals(pos.seqIndex, 1);
512 assertEquals(pos.annotationIndex, -1);
515 * cursor at bottom of second sequence
518 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
520 pos = testee.findMousePosition(evt);
521 assertEquals(pos.seqIndex, 1);
522 assertEquals(pos.annotationIndex, -1);
525 * cursor at bottom of last sequence
526 * (scale + gap + sequences)
528 y = charHeight * (2 + alignmentHeight) - 1;
529 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
531 pos = testee.findMousePosition(evt);
532 assertEquals(pos.seqIndex, alignmentHeight - 1);
533 assertEquals(pos.annotationIndex, -1);
536 * cursor below sequences, in 3-pixel gap above annotations
539 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
541 pos = testee.findMousePosition(evt);
542 assertEquals(pos.seqIndex, alignmentHeight - 1);
543 assertEquals(pos.annotationIndex, -1);
546 * cursor still in the gap above annotations, now at the bottom of it
547 * method reports index of nearest sequence above
549 y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
550 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
552 pos = testee.findMousePosition(evt);
553 assertEquals(pos.seqIndex, alignmentHeight - 1);
554 assertEquals(pos.annotationIndex, -1);
556 AlignmentAnnotation[] annotationRows = av.getAlignment().getAlignmentAnnotation();
557 for (int n = 0; n < annotationRows.length; n++)
560 * cursor at the top of the n'th annotation
563 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
565 pos = testee.findMousePosition(evt);
566 assertEquals(pos.seqIndex, alignmentHeight - 1);
567 assertEquals(pos.annotationIndex, n); // over n'th annotation
570 * cursor at the bottom of the n'th annotation
572 y += annotationRows[n].height - 1;
573 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
575 pos = testee.findMousePosition(evt);
576 SeqCanvas sc = testee.seqCanvas;
577 assertEquals(pos.seqIndex, alignmentHeight - 1,
578 String.format("%s n=%d y=%d %d, %d, %d, %d",
579 annotationRows[n].label, n, y, sc.getWidth(),
580 sc.getHeight(), sc.wrappedRepeatHeightPx,
581 sc.wrappedSpaceAboveAlignment));
582 assertEquals(pos.annotationIndex, n);
586 * cursor in gap between wrapped widths
589 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
591 pos = testee.findMousePosition(evt);
592 assertEquals(pos.seqIndex, -1);
593 assertEquals(pos.annotationIndex, -1);
596 * cursor at bottom of gap between wrapped widths
599 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
601 pos = testee.findMousePosition(evt);
602 assertEquals(pos.seqIndex, -1);
603 assertEquals(pos.annotationIndex, -1);
606 * cursor at top of scale, second wrapped width
609 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
611 pos = testee.findMousePosition(evt);
612 assertEquals(pos.seqIndex, -1);
613 assertEquals(pos.annotationIndex, -1);
616 * cursor at bottom of scale, second wrapped width
619 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
621 pos = testee.findMousePosition(evt);
622 assertEquals(pos.seqIndex, -1);
623 assertEquals(pos.annotationIndex, -1);
626 * cursor at top of first sequence, second wrapped width
629 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
631 pos = testee.findMousePosition(evt);
632 assertEquals(pos.seqIndex, 0);
633 assertEquals(pos.annotationIndex, -1);
636 @Test(groups = "Functional")
637 public void testFindMousePosition_wrapped_noAnnotations()
639 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false");
640 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
641 Cache.applicationProperties.setProperty("FONT_SIZE", "10");
642 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
643 "examples/uniref50.fa", DataSourceType.FILE);
644 AlignViewportI av = alignFrame.getViewport();
645 av.setScaleAboveWrapped(false);
646 av.setScaleLeftWrapped(false);
647 av.setScaleRightWrapped(false);
648 alignFrame.alignPanel.updateLayout();
650 final int charHeight = av.getCharHeight();
651 final int charWidth = av.getCharWidth();
652 final int alignmentHeight = av.getAlignment().getHeight();
655 assertTrue(charHeight > 0);
656 assertTrue(charWidth > 0);
657 assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
659 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
664 * mouse at top left of wrapped panel; there is a gap of charHeight
665 * above the alignment
667 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
669 MousePos pos = testee.findMousePosition(evt);
670 assertEquals(pos.column, 0);
671 assertEquals(pos.seqIndex, -1); // above sequences
672 assertEquals(pos.annotationIndex, -1);
675 * cursor over top of first sequence
678 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
680 pos = testee.findMousePosition(evt);
681 assertEquals(pos.seqIndex, 0);
682 assertEquals(pos.annotationIndex, -1);
685 * cursor at bottom of last sequence
687 y = charHeight * (1 + alignmentHeight) - 1;
688 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
690 pos = testee.findMousePosition(evt);
691 assertEquals(pos.seqIndex, alignmentHeight - 1);
692 assertEquals(pos.annotationIndex, -1);
695 * cursor below sequences, at top of charHeight gap between widths
698 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
700 pos = testee.findMousePosition(evt);
701 assertEquals(pos.seqIndex, -1);
702 assertEquals(pos.annotationIndex, -1);
705 * cursor below sequences, at top of charHeight gap between widths
708 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
710 pos = testee.findMousePosition(evt);
711 assertEquals(pos.seqIndex, -1);
712 assertEquals(pos.annotationIndex, -1);
715 * cursor at the top of the first sequence, second width
718 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
720 pos = testee.findMousePosition(evt);
721 assertEquals(pos.seqIndex, 0);
722 assertEquals(pos.annotationIndex, -1);
725 @Test(groups = "Functional")
726 public void testFindColumn_unwrapped()
728 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "false");
729 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
730 "examples/uniref50.fa", DataSourceType.FILE);
731 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
733 final int charWidth = alignFrame.getViewport().getCharWidth();
734 assertTrue(charWidth > 0); // sanity check
735 ViewportRanges ranges = alignFrame.getViewport().getRanges();
736 assertEquals(ranges.getStartRes(), 0);
739 * mouse at top left of unwrapped panel
741 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
743 assertEquals(testee.findColumn(evt), 0);
746 * not quite one charWidth across
749 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
751 assertEquals(testee.findColumn(evt), 0);
754 * one charWidth across
757 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
759 assertEquals(testee.findColumn(evt), 1);
762 * two charWidths across
765 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
767 assertEquals(testee.findColumn(evt), 2);
770 * limited to last column of seqcanvas
773 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
775 SeqCanvas seqCanvas = alignFrame.alignPanel.getSeqPanel().seqCanvas;
776 int w = seqCanvas.getWidth();
777 // limited to number of whole columns, base 0,
778 // and to end of visible range
779 int expected = w / charWidth;
780 expected = Math.min(expected, ranges.getEndRes());
781 assertEquals(testee.findColumn(evt), expected);
784 * hide columns 5-10 (base 1)
786 alignFrame.getViewport().hideColumns(4, 9);
787 x = 5 * charWidth + 2;
788 // x is in 6th visible column, absolute column 12, or 11 base 0
789 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
791 assertEquals(testee.findColumn(evt), 11);
794 @Test(groups = "Functional")
795 public void testFindColumn_wrapped()
797 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
798 AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
799 "examples/uniref50.fa", DataSourceType.FILE);
800 AlignViewport av = alignFrame.getViewport();
801 av.setScaleAboveWrapped(false);
802 av.setScaleLeftWrapped(false);
803 av.setScaleRightWrapped(false);
804 alignFrame.alignPanel.updateLayout();
805 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
807 final int charWidth = av.getCharWidth();
808 assertTrue(charWidth > 0); // sanity check
809 assertEquals(av.getRanges().getStartRes(), 0);
812 * mouse at top left of wrapped panel, no West (left) scale
814 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
816 assertEquals(testee.findColumn(evt), 0);
819 * not quite one charWidth across
822 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0,
824 assertEquals(testee.findColumn(evt), 0);
827 * one charWidth across
830 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
832 assertEquals(testee.findColumn(evt), 1);
835 * x over scale left (before drawn columns) results in -1
837 av.setScaleLeftWrapped(true);
838 alignFrame.alignPanel.updateLayout();
839 SeqCanvas seqCanvas = testee.seqCanvas;
840 int labelWidth = (int) PA.getValue(seqCanvas, "labelWidthWest");
841 assertTrue(labelWidth > 0);
843 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
845 assertEquals(testee.findColumn(evt), -1);
848 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
850 assertEquals(testee.findColumn(evt), 0);
853 * x over right edge of last residue (including scale left)
855 int residuesWide = av.getRanges().getViewportWidth();
856 assertTrue(residuesWide > 0);
857 x = labelWidth + charWidth * residuesWide - 1;
858 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
860 assertEquals(testee.findColumn(evt), residuesWide - 1);
863 * x over scale right (beyond drawn columns) results in -1
865 av.setScaleRightWrapped(true);
866 alignFrame.alignPanel.updateLayout();
867 labelWidth = (int) PA.getValue(seqCanvas, "labelWidthEast");
868 assertTrue(labelWidth > 0);
869 int residuesWide2 = av.getRanges().getViewportWidth();
870 assertTrue(residuesWide2 > 0);
871 assertTrue(residuesWide2 < residuesWide); // available width reduced
872 x += 1; // just over left edge of scale right
873 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0, 0,
875 assertEquals(testee.findColumn(evt), -1);
877 // todo add startRes offset, hidden columns
880 @BeforeClass(alwaysRun = true)
881 public static void setUpBeforeClass() throws Exception
884 * use read-only test properties file
886 Cache.loadProperties("test/jalview/io/testProps.jvprops");
887 Jalview.main(new String[] { "-nonews" });
891 * waits for Swing event dispatch queue to empty
893 synchronized void waitForSwing()
897 EventQueue.invokeAndWait(new Runnable()
904 } catch (InterruptedException | InvocationTargetException e)
909 @Test(groups = "Functional")
910 public void testFindMousePosition_wrapped_scales_longSequence()
912 Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false");
913 Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
914 Cache.applicationProperties.setProperty("FONT_SIZE", "14");
915 Cache.applicationProperties.setProperty("FONT_NAME", "SansSerif");
916 Cache.applicationProperties.setProperty("FONT_STYLE", "0");
917 // sequence of 50 bases, doubled 10 times, = 51200 bases
918 String dna = "ATGGCCATTGGGCCCAAATTTCCCAAAGGGTTTCCCTGAGGTCAGTCAGA";
919 for (int i = 0 ; i < 10 ; i++)
923 assertEquals(dna.length(), 51200);
924 AlignFrame alignFrame = new FileLoader()
925 .LoadFileWaitTillLoaded(dna, DataSourceType.PASTE);
926 SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
927 AlignViewport av = alignFrame.getViewport();
928 av.setScaleAboveWrapped(true);
929 av.setScaleLeftWrapped(true);
930 av.setScaleRightWrapped(true);
931 alignFrame.alignPanel.updateLayout();
936 } catch (InterruptedException e)
940 final int charHeight = av.getCharHeight();
941 final int charWidth = av.getCharWidth();
942 assertEquals(charHeight, 17);
943 assertEquals(charWidth, 12);
945 FontMetrics fm = testee.getFontMetrics(av.getFont());
946 int labelWidth = fm.stringWidth("00000") + charWidth;
947 assertEquals(labelWidth, 57); // 5 x 9 + charWidth
948 assertEquals(testee.seqCanvas.getLabelWidthWest(), labelWidth);
954 * mouse at top left of wrapped panel; there is a gap of 2 * charHeight
955 * above the alignment
957 MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y,
959 MousePos pos = testee.findMousePosition(evt);
960 assertEquals(pos.column, -1); // over scale left, not an alignment column
961 assertEquals(pos.seqIndex, -1); // above sequences
962 assertEquals(pos.annotationIndex, -1);
965 * cursor over scale above first sequence
969 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
971 pos = testee.findMousePosition(evt);
972 assertEquals(pos.seqIndex, -1);
973 assertEquals(pos.column, 0);
974 assertEquals(pos.annotationIndex, -1);
977 * cursor over scale left of first sequence
981 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
983 pos = testee.findMousePosition(evt);
984 assertEquals(pos.seqIndex, 0);
985 assertEquals(pos.column, -1);
986 assertEquals(pos.annotationIndex, -1);
989 * cursor over start of first sequence
992 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
994 pos = testee.findMousePosition(evt);
995 assertEquals(pos.seqIndex, 0);
996 assertEquals(pos.column, 0);
997 assertEquals(pos.annotationIndex, -1);
1000 * move one character right, to bottom pixel of same row
1003 y += charHeight - 1;
1004 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1006 pos = testee.findMousePosition(evt);
1007 assertEquals(pos.seqIndex, 0);
1008 assertEquals(pos.column, 1);
1011 * move down one pixel - now in the no man's land between rows
1014 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1016 pos = testee.findMousePosition(evt);
1017 assertEquals(pos.seqIndex, -1);
1018 assertEquals(pos.column, 1);
1021 * move down two char heights less one pixel - still in the no man's land
1022 * (scale above + spacer line)
1024 y += (2 * charHeight - 1);
1025 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1027 pos = testee.findMousePosition(evt);
1028 assertEquals(pos.seqIndex, -1);
1029 assertEquals(pos.column, 1);
1032 * move down one more pixel - now on the next row of the sequence
1035 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1037 pos = testee.findMousePosition(evt);
1038 assertEquals(pos.seqIndex, 0);
1039 assertEquals(pos.column, 1 + av.getWrappedWidth());
1042 * scroll to near the end of the sequence
1044 SearchResultsI sr = new SearchResults();
1045 int scrollTo = dna.length() - 1000;
1046 sr.addResult(av.getAlignment().getSequenceAt(0), scrollTo, scrollTo);
1047 alignFrame.alignPanel.scrollToPosition(sr);
1050 * place the mouse on the first column of the 6th sequence, and
1051 * verify that (computed) findMousePosition matches (actual) ViewportRanges
1054 y = 17 * charHeight; // 17 = 6 times two header rows and 5 sequence rows
1055 evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, y, 0, 0, 0,
1057 pos = testee.findMousePosition(evt);
1058 assertEquals(pos.seqIndex, 0);
1059 int expected = av.getRanges().getStartRes() + 5 * av.getWrappedWidth();
1060 assertEquals(pos.column, expected);