From 83c47970701adc1cd6100332544f7f563e71f8f5 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Tue, 2 Oct 2018 17:08:07 +0100 Subject: [PATCH] JAL-3093 unit tests for SeqPanel.findMousePosition --- src/jalview/gui/SeqCanvas.java | 9 +- src/jalview/gui/SeqPanel.java | 26 +- test/jalview/gui/SeqPanelTest.java | 497 ++++++++++++++++++++++++++++++++++++ 3 files changed, 518 insertions(+), 14 deletions(-) diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 5c404f0..31c8a47 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -55,6 +55,11 @@ import javax.swing.JComponent; */ public class SeqCanvas extends JComponent implements ViewportListenerI { + /* + * pixels gap between sequences and annotations when in wrapped mode + */ + static final int SEQS_ANNOTATION_GAP = 3; + private static final String ZEROS = "0000000000"; final FeatureRenderer fr; @@ -705,7 +710,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.isShowAnnotation()) { - g.translate(0, cHeight + ypos + 3); + g.translate(0, cHeight + ypos + SEQS_ANNOTATION_GAP); if (annotations == null) { annotations = new AnnotationPanel(av); @@ -713,7 +718,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI annotations.renderer.drawComponent(annotations, av, g, -1, startColumn, endx + 1); - g.translate(0, -cHeight - ypos - 3); + g.translate(0, -cHeight - ypos - SEQS_ANNOTATION_GAP); } g.setClip(clip); g.translate(-xOffset, 0); diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 3f740a1..0b62629 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -255,7 +255,7 @@ public class SeqPanel extends JPanel int wrappedBlock = -1; /** - * Computes the column and sequence row (or possibly annotation row when in + * Computes the column and sequence row (and possibly annotation row when in * wrapped mode) for the given mouse position * * @param evt @@ -264,7 +264,7 @@ public class SeqPanel extends JPanel MousePos findMousePosition(MouseEvent evt) { int col = findColumn(evt); - int seq = -1; + int seqIndex = -1; int annIndex = -1; int y = evt.getY(); @@ -280,20 +280,23 @@ public class SeqPanel extends JPanel final int alignmentHeightPixels = alignmentHeight * charHeight + hgap; final int annotationHeight = seqCanvas.getAnnotationHeight(); - final int cHeight = alignmentHeightPixels + annotationHeight; + final int cHeight = alignmentHeightPixels + annotationHeight + + SeqCanvas.SEQS_ANNOTATION_GAP; int yOffsetPx = y % cHeight; // yPos below repeating width(s) - if (yOffsetPx > alignmentHeightPixels) + if (yOffsetPx >= alignmentHeightPixels + + SeqCanvas.SEQS_ANNOTATION_GAP) { /* - * mouse is over annotations + * mouse is over annotations; find annotation index, also + * last sequence above (for backwards compatible behaviour) */ AlignmentAnnotation[] anns = av.getAlignment() .getAlignmentAnnotation(); - int rowOffsetPx = yOffsetPx - alignmentHeightPixels; + int rowOffsetPx = yOffsetPx - alignmentHeightPixels + - SeqCanvas.SEQS_ANNOTATION_GAP; annIndex = AnnotationPanel.getRowIndex(rowOffsetPx, anns); - // also last sequence in alignment (for backwards compatible behaviour) - seq = alignmentHeight - 1; + seqIndex = alignmentHeight - 1; } else { @@ -301,18 +304,17 @@ public class SeqPanel extends JPanel * mouse is over sequence (or the space above sequences) */ yOffsetPx -= hgap; - if (yOffsetPx > 0) + if (yOffsetPx >= 0) { - seq = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); + seqIndex = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); } } } else { - seq = Math.min((y / charHeight) + av.getRanges().getStartSeq(), + seqIndex = Math.min((y / charHeight) + av.getRanges().getStartSeq(), alignmentHeight - 1); } - int seqIndex = seq; return new MousePos(col, seqIndex, annIndex); } diff --git a/test/jalview/gui/SeqPanelTest.java b/test/jalview/gui/SeqPanelTest.java index a5d244d..4177acc 100644 --- a/test/jalview/gui/SeqPanelTest.java +++ b/test/jalview/gui/SeqPanelTest.java @@ -21,12 +21,23 @@ package jalview.gui; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import jalview.api.AlignViewportI; +import jalview.bin.Cache; +import jalview.bin.Jalview; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; +import jalview.gui.SeqPanel.MousePos; +import jalview.io.DataSourceType; +import jalview.io.FileLoader; +import java.awt.Event; +import java.awt.event.MouseEvent; + +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -88,4 +99,490 @@ public class SeqPanelTest assertEquals(alignFrame.statusBar.getText(), "Sequence 2 ID: Seq2 Residue: B (2)"); } + + @Test(groups = "Functional") + public void testFindMousePosition_unwrapped() + { + String seqData = ">Seq1\nAACDE\n>Seq2\nAA--E\n"; + AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(seqData, + DataSourceType.PASTE); + AlignViewportI av = alignFrame.getViewport(); + av.setShowAnnotation(true); + av.setWrapAlignment(false); + final int charHeight = av.getCharHeight(); + final int charWidth = av.getCharWidth(); + // sanity checks: + assertTrue(charHeight > 0); + assertTrue(charWidth > 0); + assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0); + + SeqPanel testee = alignFrame.alignPanel.getSeqPanel(); + int x = 0; + int y = 0; + + /* + * mouse at top left of unwrapped panel + */ + MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, + 0, 0, 0, false, 0); + MousePos pos = testee.findMousePosition(evt); + assertEquals(pos.column, 0); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + } + + @AfterMethod(alwaysRun = true) + public void tearDown() + { + Desktop.instance.closeAll_actionPerformed(null); + } + + @Test(groups = "Functional") + public void testFindMousePosition_wrapped() + { + Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true"); + Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( + "examples/uniref50.fa", DataSourceType.FILE); + AlignViewportI av = alignFrame.getViewport(); + av.setScaleAboveWrapped(false); + av.setScaleLeftWrapped(false); + av.setScaleRightWrapped(false); + alignFrame.alignPanel.paintAlignment(false, false); + + final int charHeight = av.getCharHeight(); + final int charWidth = av.getCharWidth(); + final int alignmentHeight = av.getAlignment().getHeight(); + + // sanity checks: + assertTrue(charHeight > 0); + assertTrue(charWidth > 0); + assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0); + + SeqPanel testee = alignFrame.alignPanel.getSeqPanel(); + int x = 0; + int y = 0; + + /* + * mouse at top left of wrapped panel; there is a gap of charHeight + * above the alignment + */ + MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, + 0, 0, 0, false, 0); + MousePos pos = testee.findMousePosition(evt); + assertEquals(pos.column, 0); + assertEquals(pos.seqIndex, -1); // above sequences + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of gap above + */ + y = charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor over top of first sequence + */ + y = charHeight; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of first sequence + */ + y = 2 * charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at top of second sequence + */ + y = 2 * charHeight; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of second sequence + */ + y = 3 * charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of last sequence + */ + y = charHeight * (1 + alignmentHeight) - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor below sequences, in 3-pixel gap above annotations + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor still in the gap above annotations, now at the bottom of it + * method reports index of nearest sequence above + */ + y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2 + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at the top of the first annotation + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 0); // over first annotation + + /* + * cursor at the bottom of the first annotation + */ + y += av.getAlignment().getAlignmentAnnotation()[0].height - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 0); + + /* + * cursor at the top of the second annotation + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 1); + + /* + * cursor at the bottom of the second annotation + */ + y += av.getAlignment().getAlignmentAnnotation()[1].height - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 1); + + /* + * cursor at the top of the third annotation + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 2); + + /* + * cursor at the bottom of the third annotation + */ + y += av.getAlignment().getAlignmentAnnotation()[2].height - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 2); + + /* + * cursor in gap between wrapped widths + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of gap between wrapped widths + */ + y += charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at top of first sequence, second wrapped width + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + } + + @Test(groups = "Functional") + public void testFindMousePosition_wrapped_scaleAbove() + { + Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true"); + Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true"); + AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded( + "examples/uniref50.fa", DataSourceType.FILE); + AlignViewportI av = alignFrame.getViewport(); + av.setScaleAboveWrapped(true); + av.setScaleLeftWrapped(false); + av.setScaleRightWrapped(false); + alignFrame.alignPanel.paintAlignment(false, false); + + final int charHeight = av.getCharHeight(); + final int charWidth = av.getCharWidth(); + final int alignmentHeight = av.getAlignment().getHeight(); + + // sanity checks: + assertTrue(charHeight > 0); + assertTrue(charWidth > 0); + assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0); + + SeqPanel testee = alignFrame.alignPanel.getSeqPanel(); + int x = 0; + int y = 0; + + /* + * mouse at top left of wrapped panel; there is a gap of charHeight + * above the alignment + */ + MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, + 0, 0, 0, false, 0); + MousePos pos = testee.findMousePosition(evt); + assertEquals(pos.column, 0); + assertEquals(pos.seqIndex, -1); // above sequences + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of gap above + * two charHeights including scale panel + */ + y = 2 * charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor over top of first sequence + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of first sequence + */ + y += charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at top of second sequence + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of second sequence + */ + y += charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of last sequence + * (scale + gap + sequences) + */ + y = charHeight * (2 + alignmentHeight) - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor below sequences, in 3-pixel gap above annotations + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor still in the gap above annotations, now at the bottom of it + * method reports index of nearest sequence above + */ + y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2 + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at the top of the first annotation + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 0); // over first annotation + + /* + * cursor at the bottom of the first annotation + */ + y += av.getAlignment().getAlignmentAnnotation()[0].height - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 0); + + /* + * cursor at the top of the second annotation + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 1); + + /* + * cursor at the bottom of the second annotation + */ + y += av.getAlignment().getAlignmentAnnotation()[1].height - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 1); + + /* + * cursor at the top of the third annotation + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 2); + + /* + * cursor at the bottom of the third annotation + */ + y += av.getAlignment().getAlignmentAnnotation()[2].height - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, alignmentHeight - 1); + assertEquals(pos.annotationIndex, 2); + + /* + * cursor in gap between wrapped widths + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of gap between wrapped widths + */ + y += charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at top of scale, second wrapped width + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at bottom of scale, second wrapped width + */ + y += charHeight - 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, -1); + assertEquals(pos.annotationIndex, -1); + + /* + * cursor at top of first sequence, second wrapped width + */ + y += 1; + evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0, + false, 0); + pos = testee.findMousePosition(evt); + assertEquals(pos.seqIndex, 0); + assertEquals(pos.annotationIndex, -1); + } + @BeforeClass(alwaysRun = true) + public static void setUpBeforeClass() throws Exception + { + /* + * use read-only test properties file + */ + Cache.loadProperties("test/jalview/io/testProps.jvprops"); + Jalview.main(new String[] { "-nonews" }); + } } -- 1.7.10.2