JAL-3093 unit test adapts to actual number of annotation rows
[jalview.git] / test / jalview / gui / SeqPanelTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.gui;
22
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertTrue;
25
26 import jalview.api.AlignViewportI;
27 import jalview.bin.Cache;
28 import jalview.bin.Jalview;
29 import jalview.datamodel.Alignment;
30 import jalview.datamodel.AlignmentAnnotation;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.Sequence;
33 import jalview.datamodel.SequenceI;
34 import jalview.gui.SeqPanel.MousePos;
35 import jalview.io.DataSourceType;
36 import jalview.io.FileLoader;
37
38 import java.awt.Event;
39 import java.awt.EventQueue;
40 import java.awt.event.MouseEvent;
41 import java.lang.reflect.InvocationTargetException;
42
43 import javax.swing.JLabel;
44
45 import org.testng.annotations.AfterMethod;
46 import org.testng.annotations.BeforeClass;
47 import org.testng.annotations.Test;
48
49 import junit.extensions.PA;
50
51 public class SeqPanelTest
52 {
53   AlignFrame af;
54
55   @BeforeClass(alwaysRun = true)
56   public void setUpJvOptionPane()
57   {
58     JvOptionPane.setInteractiveMode(false);
59     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
60   }
61   @Test(groups = "Functional")
62   public void testSetStatusReturnsNearestResiduePosition()
63   {
64     SequenceI seq1 = new Sequence("Seq1", "AACDE");
65     SequenceI seq2 = new Sequence("Seq2", "AA--E");
66     AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
67     AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
68             al.getHeight());
69     AlignmentI visAl = alignFrame.getViewport().getAlignment();
70
71     // Test either side of gap
72     assertEquals(
73             alignFrame.alignPanel.getSeqPanel().setStatusMessage(
74                     visAl.getSequenceAt(1), 1, 1), 2);
75     assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
76             "Sequence 2 ID: Seq2 Residue: ALA (2)");
77     assertEquals(
78             alignFrame.alignPanel.getSeqPanel().setStatusMessage(
79                     visAl.getSequenceAt(1), 4, 1), 3);
80     assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
81             "Sequence 2 ID: Seq2 Residue: GLU (3)");
82     // no status message at a gap, returns next residue position to the right
83     assertEquals(
84             alignFrame.alignPanel.getSeqPanel().setStatusMessage(
85                     visAl.getSequenceAt(1), 2, 1), 3);
86     assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
87             "Sequence 2 ID: Seq2");
88     assertEquals(
89             alignFrame.alignPanel.getSeqPanel().setStatusMessage(
90                     visAl.getSequenceAt(1), 3, 1), 3);
91     assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
92             "Sequence 2 ID: Seq2");
93   }
94
95   @Test(groups = "Functional")
96   public void testAmbiguousAminoAcidGetsStatusMessage()
97   {
98     SequenceI seq1 = new Sequence("Seq1", "ABCDE");
99     SequenceI seq2 = new Sequence("Seq2", "AB--E");
100     AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
101     AlignFrame alignFrame = new AlignFrame(al, al.getWidth(),
102             al.getHeight());
103     AlignmentI visAl = alignFrame.getViewport().getAlignment();
104
105     assertEquals(
106             alignFrame.alignPanel.getSeqPanel().setStatusMessage(
107                     visAl.getSequenceAt(1), 1, 1), 2);
108     assertEquals(((JLabel) PA.getValue(alignFrame, "statusBar")).getText(),
109             "Sequence 2 ID: Seq2 Residue: B (2)");
110   }
111
112   @Test(groups = "Functional")
113   public void testFindMousePosition_unwrapped()
114   {
115     String seqData = ">Seq1\nAACDE\n>Seq2\nAA--E\n";
116     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(seqData,
117             DataSourceType.PASTE);
118     AlignViewportI av = alignFrame.getViewport();
119     av.setShowAnnotation(true);
120     av.setWrapAlignment(false);
121     final int charHeight = av.getCharHeight();
122     final int charWidth = av.getCharWidth();
123     // sanity checks:
124     assertTrue(charHeight > 0);
125     assertTrue(charWidth > 0);
126     assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
127
128     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
129     int x = 0;
130     int y = 0;
131
132     /*
133      * mouse at top left of unwrapped panel
134      */
135     MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
136             0, 0, 0, false, 0);
137     MousePos pos = testee.findMousePosition(evt);
138     assertEquals(pos.column, 0);
139     assertEquals(pos.seqIndex, 0);
140     assertEquals(pos.annotationIndex, -1);
141   }
142
143   @AfterMethod(alwaysRun = true)
144   public void tearDown()
145   {
146     Desktop.instance.closeAll_actionPerformed(null);
147   }
148
149   @Test(groups = "Functional")
150   public void testFindMousePosition_wrapped_annotations()
151   {
152     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
153     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
154     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
155             "examples/uniref50.fa", DataSourceType.FILE);
156     AlignViewportI av = alignFrame.getViewport();
157     av.setScaleAboveWrapped(false);
158     av.setScaleLeftWrapped(false);
159     av.setScaleRightWrapped(false);
160     alignFrame.alignPanel.paintAlignment(false, false);
161     waitForSwing(); // for Swing thread
162
163     final int charHeight = av.getCharHeight();
164     final int charWidth = av.getCharWidth();
165     final int alignmentHeight = av.getAlignment().getHeight();
166     
167     // sanity checks:
168     assertTrue(charHeight > 0);
169     assertTrue(charWidth > 0);
170     assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
171   
172     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
173     int x = 0;
174     int y = 0;
175   
176     /*
177      * mouse at top left of wrapped panel; there is a gap of charHeight
178      * above the alignment
179      */
180     MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
181             0, 0, 0, false, 0);
182     MousePos pos = testee.findMousePosition(evt);
183     assertEquals(pos.column, 0);
184     assertEquals(pos.seqIndex, -1); // above sequences
185     assertEquals(pos.annotationIndex, -1);
186
187     /*
188      * cursor at bottom of gap above
189      */
190     y = charHeight - 1;
191     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
192             false, 0);
193     pos = testee.findMousePosition(evt);
194     assertEquals(pos.seqIndex, -1);
195     assertEquals(pos.annotationIndex, -1);
196
197     /*
198      * cursor over top of first sequence
199      */
200     y = charHeight;
201     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
202             false, 0);
203     pos = testee.findMousePosition(evt);
204     assertEquals(pos.seqIndex, 0);
205     assertEquals(pos.annotationIndex, -1);
206
207     /*
208      * cursor at bottom of first sequence
209      */
210     y = 2 * charHeight - 1;
211     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
212             false, 0);
213     pos = testee.findMousePosition(evt);
214     assertEquals(pos.seqIndex, 0);
215     assertEquals(pos.annotationIndex, -1);
216
217     /*
218      * cursor at top of second sequence
219      */
220     y = 2 * charHeight;
221     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
222             false, 0);
223     pos = testee.findMousePosition(evt);
224     assertEquals(pos.seqIndex, 1);
225     assertEquals(pos.annotationIndex, -1);
226
227     /*
228      * cursor at bottom of second sequence
229      */
230     y = 3 * charHeight - 1;
231     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
232             false, 0);
233     pos = testee.findMousePosition(evt);
234     assertEquals(pos.seqIndex, 1);
235     assertEquals(pos.annotationIndex, -1);
236
237     /*
238      * cursor at bottom of last sequence
239      */
240     y = charHeight * (1 + alignmentHeight) - 1;
241     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
242             false, 0);
243     pos = testee.findMousePosition(evt);
244     assertEquals(pos.seqIndex, alignmentHeight - 1);
245     assertEquals(pos.annotationIndex, -1);
246
247     /*
248      * cursor below sequences, in 3-pixel gap above annotations
249      * method reports index of nearest sequence above
250      */
251     y += 1;
252     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
253             false, 0);
254     pos = testee.findMousePosition(evt);
255     assertEquals(pos.seqIndex, alignmentHeight - 1);
256     assertEquals(pos.annotationIndex, -1);
257
258     /*
259      * cursor still in the gap above annotations, now at the bottom of it
260      */
261     y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
262     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
263             false, 0);
264     pos = testee.findMousePosition(evt);
265     assertEquals(pos.seqIndex, alignmentHeight - 1);
266     assertEquals(pos.annotationIndex, -1);
267
268     AlignmentAnnotation[] annotationRows = av.getAlignment()
269             .getAlignmentAnnotation();
270     for (int n = 0; n < annotationRows.length; n++)
271     {
272       /*
273        * cursor at the top of the n'th annotation  
274        */
275       y += 1;
276       evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
277               false, 0);
278       pos = testee.findMousePosition(evt);
279       assertEquals(pos.seqIndex, alignmentHeight - 1);
280       assertEquals(pos.annotationIndex, n); // over n'th annotation
281
282       /*
283        * cursor at the bottom of the n'th annotation  
284        */
285       y += annotationRows[n].height - 1;
286       evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
287               false, 0);
288       pos = testee.findMousePosition(evt);
289       assertEquals(pos.seqIndex, alignmentHeight - 1);
290       assertEquals(pos.annotationIndex, n);
291     }
292
293     /*
294      * cursor in gap between wrapped widths  
295      */
296     y += 1;
297     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
298             false, 0);
299     pos = testee.findMousePosition(evt);
300     assertEquals(pos.seqIndex, -1);
301     assertEquals(pos.annotationIndex, -1);
302
303     /*
304      * cursor at bottom of gap between wrapped widths  
305      */
306     y += charHeight - 1;
307     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
308             false, 0);
309     pos = testee.findMousePosition(evt);
310     assertEquals(pos.seqIndex, -1);
311     assertEquals(pos.annotationIndex, -1);
312
313     /*
314      * cursor at top of first sequence, second wrapped width  
315      */
316     y += 1;
317     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
318             false, 0);
319     pos = testee.findMousePosition(evt);
320     assertEquals(pos.seqIndex, 0);
321     assertEquals(pos.annotationIndex, -1);
322   }
323
324   @Test(groups = "Functional")
325   public void testFindMousePosition_wrapped_scaleAbove()
326   {
327     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
328     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
329     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
330             "examples/uniref50.fa", DataSourceType.FILE);
331     AlignViewportI av = alignFrame.getViewport();
332     av.setScaleAboveWrapped(true);
333     av.setScaleLeftWrapped(false);
334     av.setScaleRightWrapped(false);
335     alignFrame.alignPanel.paintAlignment(false, false);
336     waitForSwing();
337
338     final int charHeight = av.getCharHeight();
339     final int charWidth = av.getCharWidth();
340     final int alignmentHeight = av.getAlignment().getHeight();
341     
342     // sanity checks:
343     assertTrue(charHeight > 0);
344     assertTrue(charWidth > 0);
345     assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
346   
347     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
348     int x = 0;
349     int y = 0;
350   
351     /*
352      * mouse at top left of wrapped panel; there is a gap of charHeight
353      * above the alignment
354      */
355     MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
356             0, 0, 0, false, 0);
357     MousePos pos = testee.findMousePosition(evt);
358     assertEquals(pos.column, 0);
359     assertEquals(pos.seqIndex, -1); // above sequences
360     assertEquals(pos.annotationIndex, -1);
361   
362     /*
363      * cursor at bottom of gap above
364      * two charHeights including scale panel
365      */
366     y = 2 * charHeight - 1;
367     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
368             false, 0);
369     pos = testee.findMousePosition(evt);
370     assertEquals(pos.seqIndex, -1);
371     assertEquals(pos.annotationIndex, -1);
372   
373     /*
374      * cursor over top of first sequence
375      */
376     y += 1;
377     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
378             false, 0);
379     pos = testee.findMousePosition(evt);
380     assertEquals(pos.seqIndex, 0);
381     assertEquals(pos.annotationIndex, -1);
382   
383     /*
384      * cursor at bottom of first sequence
385      */
386     y += charHeight - 1;
387     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
388             false, 0);
389     pos = testee.findMousePosition(evt);
390     assertEquals(pos.seqIndex, 0);
391     assertEquals(pos.annotationIndex, -1);
392   
393     /*
394      * cursor at top of second sequence
395      */
396     y += 1;
397     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
398             false, 0);
399     pos = testee.findMousePosition(evt);
400     assertEquals(pos.seqIndex, 1);
401     assertEquals(pos.annotationIndex, -1);
402   
403     /*
404      * cursor at bottom of second sequence
405      */
406     y += charHeight - 1;
407     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
408             false, 0);
409     pos = testee.findMousePosition(evt);
410     assertEquals(pos.seqIndex, 1);
411     assertEquals(pos.annotationIndex, -1);
412   
413     /*
414      * cursor at bottom of last sequence
415      * (scale + gap + sequences)
416      */
417     y = charHeight * (2 + alignmentHeight) - 1;
418     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
419             false, 0);
420     pos = testee.findMousePosition(evt);
421     assertEquals(pos.seqIndex, alignmentHeight - 1);
422     assertEquals(pos.annotationIndex, -1);
423   
424     /*
425      * cursor below sequences, in 3-pixel gap above annotations
426      */
427     y += 1;
428     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
429             false, 0);
430     pos = testee.findMousePosition(evt);
431     assertEquals(pos.seqIndex, alignmentHeight - 1);
432     assertEquals(pos.annotationIndex, -1);
433   
434     /*
435      * cursor still in the gap above annotations, now at the bottom of it
436      * method reports index of nearest sequence above  
437      */
438     y += SeqCanvas.SEQS_ANNOTATION_GAP - 1; // 3-1 = 2
439     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
440             false, 0);
441     pos = testee.findMousePosition(evt);
442     assertEquals(pos.seqIndex, alignmentHeight - 1);
443     assertEquals(pos.annotationIndex, -1);
444   
445     AlignmentAnnotation[] annotationRows = av.getAlignment().getAlignmentAnnotation();
446     for (int n = 0; n < annotationRows.length; n++)
447     {
448       /*
449        * cursor at the top of the n'th annotation  
450        */
451       y += 1;
452       evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
453               false, 0);
454       pos = testee.findMousePosition(evt);
455       assertEquals(pos.seqIndex, alignmentHeight - 1);
456       assertEquals(pos.annotationIndex, n); // over n'th annotation
457
458       /*
459        * cursor at the bottom of the n'th annotation  
460        */
461       y += annotationRows[n].height - 1;
462       evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
463               false, 0);
464       pos = testee.findMousePosition(evt);
465       assertEquals(pos.seqIndex, alignmentHeight - 1);
466       assertEquals(pos.annotationIndex, n);
467     }
468   
469     /*
470      * cursor in gap between wrapped widths  
471      */
472     y += 1;
473     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
474             false, 0);
475     pos = testee.findMousePosition(evt);
476     assertEquals(pos.seqIndex, -1);
477     assertEquals(pos.annotationIndex, -1);
478   
479     /*
480      * cursor at bottom of gap between wrapped widths  
481      */
482     y += charHeight - 1;
483     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
484             false, 0);
485     pos = testee.findMousePosition(evt);
486     assertEquals(pos.seqIndex, -1);
487     assertEquals(pos.annotationIndex, -1);
488   
489     /*
490      * cursor at top of scale, second wrapped width  
491      */
492     y += 1;
493     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
494             false, 0);
495     pos = testee.findMousePosition(evt);
496     assertEquals(pos.seqIndex, -1);
497     assertEquals(pos.annotationIndex, -1);
498
499     /*
500      * cursor at bottom of scale, second wrapped width  
501      */
502     y += charHeight - 1;
503     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
504             false, 0);
505     pos = testee.findMousePosition(evt);
506     assertEquals(pos.seqIndex, -1);
507     assertEquals(pos.annotationIndex, -1);
508
509     /*
510      * cursor at top of first sequence, second wrapped width  
511      */
512     y += 1;
513     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
514             false, 0);
515     pos = testee.findMousePosition(evt);
516     assertEquals(pos.seqIndex, 0);
517     assertEquals(pos.annotationIndex, -1);
518   }
519
520   @Test(groups = "Functional")
521   public void testFindMousePosition_wrapped_noAnnotations()
522   {
523     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false");
524     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
525     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
526             "examples/uniref50.fa", DataSourceType.FILE);
527     AlignViewportI av = alignFrame.getViewport();
528     av.setScaleAboveWrapped(false);
529     av.setScaleLeftWrapped(false);
530     av.setScaleRightWrapped(false);
531     alignFrame.alignPanel.paintAlignment(false, false);
532     waitForSwing();
533
534     final int charHeight = av.getCharHeight();
535     final int charWidth = av.getCharWidth();
536     final int alignmentHeight = av.getAlignment().getHeight();
537     
538     // sanity checks:
539     assertTrue(charHeight > 0);
540     assertTrue(charWidth > 0);
541     assertTrue(alignFrame.alignPanel.getSeqPanel().getWidth() > 0);
542   
543     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
544     int x = 0;
545     int y = 0;
546   
547     /*
548      * mouse at top left of wrapped panel; there is a gap of charHeight
549      * above the alignment
550      */
551     MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y,
552             0, 0, 0, false, 0);
553     MousePos pos = testee.findMousePosition(evt);
554     assertEquals(pos.column, 0);
555     assertEquals(pos.seqIndex, -1); // above sequences
556     assertEquals(pos.annotationIndex, -1);
557   
558     /*
559      * cursor over top of first sequence
560      */
561     y = charHeight;
562     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
563             false, 0);
564     pos = testee.findMousePosition(evt);
565     assertEquals(pos.seqIndex, 0);
566     assertEquals(pos.annotationIndex, -1);
567
568     /*
569      * cursor at bottom of last sequence
570      */
571     y = charHeight * (1 + alignmentHeight) - 1;
572     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
573             false, 0);
574     pos = testee.findMousePosition(evt);
575     assertEquals(pos.seqIndex, alignmentHeight - 1);
576     assertEquals(pos.annotationIndex, -1);
577   
578     /*
579      * cursor below sequences, at top of charHeight gap between widths
580      */
581     y += 1;
582     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
583             false, 0);
584     pos = testee.findMousePosition(evt);
585     assertEquals(pos.seqIndex, -1);
586     assertEquals(pos.annotationIndex, -1);
587   
588     /*
589      * cursor below sequences, at top of charHeight gap between widths
590      */
591     y += charHeight - 1;
592     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
593             false, 0);
594     pos = testee.findMousePosition(evt);
595     assertEquals(pos.seqIndex, -1);
596     assertEquals(pos.annotationIndex, -1);
597   
598     /*
599      * cursor at the top of the first sequence, second width  
600      */
601     y += 1;
602     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, y, 0, 0, 0,
603             false, 0);
604     pos = testee.findMousePosition(evt);
605     assertEquals(pos.seqIndex, 0);
606     assertEquals(pos.annotationIndex, -1);
607   }
608
609   @Test(groups = "Functional")
610   public void testFindColumn_unwrapped()
611   {
612     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "false");
613     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
614             "examples/uniref50.fa", DataSourceType.FILE);
615     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
616     int x = 0;
617     final int charWidth = alignFrame.getViewport().getCharWidth();
618     assertTrue(charWidth > 0); // sanity check
619     assertEquals(alignFrame.getViewport().getRanges().getStartRes(), 0);
620
621     /*
622      * mouse at top left of unwrapped panel
623      */
624     MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
625             0, 0, 0, false, 0);
626     assertEquals(testee.findColumn(evt), 0);
627     
628     /*
629      * not quite one charWidth across
630      */
631     x = charWidth-1;
632     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
633             0, 0, 0, false, 0);
634     assertEquals(testee.findColumn(evt), 0);
635
636     /*
637      * one charWidth across
638      */
639     x = charWidth;
640     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
641             false, 0);
642     assertEquals(testee.findColumn(evt), 1);
643
644     /*
645      * two charWidths across
646      */
647     x = 2 * charWidth;
648     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
649             false, 0);
650     assertEquals(testee.findColumn(evt), 2);
651
652     /*
653      * limited to last column of seqcanvas
654      */
655     x = 20000;
656     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
657             false, 0);
658     SeqCanvas seqCanvas = alignFrame.alignPanel.getSeqPanel().seqCanvas;
659     int w = seqCanvas.getWidth();
660     // limited to number of whole columns, base 0
661     int expected = w / charWidth - 1;
662     assertEquals(testee.findColumn(evt), expected);
663
664     /*
665      * hide columns 5-10 (base 1)
666      */
667     alignFrame.getViewport().hideColumns(4, 9);
668     x = 5 * charWidth + 2;
669     // x is in 6th visible column, absolute column 12, or 11 base 0
670     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
671             false, 0);
672     assertEquals(testee.findColumn(evt), 11);
673   }
674
675   @Test(groups = "Functional")
676   public void testFindColumn_wrapped()
677   {
678     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
679     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
680             "examples/uniref50.fa", DataSourceType.FILE);
681     AlignViewport av = alignFrame.getViewport();
682     av.setScaleAboveWrapped(false);
683     av.setScaleLeftWrapped(false);
684     av.setScaleRightWrapped(false);
685     alignFrame.alignPanel.paintAlignment(false, false);
686     // need to wait for repaint to finish!
687     waitForSwing();
688     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
689     int x = 0;
690     final int charWidth = av.getCharWidth();
691     assertTrue(charWidth > 0); // sanity check
692     assertEquals(av.getRanges().getStartRes(), 0);
693   
694     /*
695      * mouse at top left of wrapped panel, no West (left) scale
696      */
697     MouseEvent evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
698             0, 0, 0, false, 0);
699     assertEquals(testee.findColumn(evt), 0);
700     
701     /*
702      * not quite one charWidth across
703      */
704     x = charWidth-1;
705     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0,
706             0, 0, 0, false, 0);
707     assertEquals(testee.findColumn(evt), 0);
708   
709     /*
710      * one charWidth across
711      */
712     x = charWidth;
713     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
714             false, 0);
715     assertEquals(testee.findColumn(evt), 1);
716
717     /*
718      * x over scale left (before drawn columns) results in -1
719      */
720     av.setScaleLeftWrapped(true);
721     alignFrame.alignPanel.paintAlignment(false, false);
722     waitForSwing();
723     SeqCanvas seqCanvas = testee.seqCanvas;
724     int labelWidth = (int) PA.getValue(seqCanvas, "labelWidthWest");
725     assertTrue(labelWidth > 0);
726     x = labelWidth - 1;
727     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
728             false, 0);
729     assertEquals(testee.findColumn(evt), -1);
730
731     x = labelWidth;
732     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
733             false, 0);
734     assertEquals(testee.findColumn(evt), 0);
735
736     /*
737      * x over right edge of last residue (including scale left)
738      */
739     int residuesWide = av.getRanges().getViewportWidth();
740     assertTrue(residuesWide > 0);
741     x = labelWidth + charWidth * residuesWide - 1;
742     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
743             false, 0);
744     assertEquals(testee.findColumn(evt), residuesWide - 1);
745
746     /*
747      * x over scale right (beyond drawn columns) results in -1
748      */
749     av.setScaleRightWrapped(true);
750     alignFrame.alignPanel.paintAlignment(false, false);
751     waitForSwing();
752     labelWidth = (int) PA.getValue(seqCanvas, "labelWidthEast");
753     assertTrue(labelWidth > 0);
754     int residuesWide2 = av.getRanges().getViewportWidth();
755     assertTrue(residuesWide2 > 0);
756     assertTrue(residuesWide2 < residuesWide); // available width reduced
757     x += 1; // just over left edge of scale right
758     evt = new MouseEvent(testee, Event.MOUSE_MOVE, 0L, 0, x, 0, 0, 0, 0,
759             false, 0);
760     assertEquals(testee.findColumn(evt), -1);
761     
762     // todo add startRes offset, hidden columns
763
764   }
765   @BeforeClass(alwaysRun = true)
766   public static void setUpBeforeClass() throws Exception
767   {
768     /*
769      * use read-only test properties file
770      */
771     Cache.loadProperties("test/jalview/io/testProps.jvprops");
772     Jalview.main(new String[] { "-nonews" });
773   }
774
775   /**
776    * waits for Swing event dispatch queue to empty
777    */
778   synchronized void waitForSwing()
779   {
780     try
781     {
782       EventQueue.invokeAndWait(new Runnable()
783       {
784         @Override
785         public void run()
786         {
787         }
788       });
789     } catch (InterruptedException | InvocationTargetException e)
790     {
791       e.printStackTrace();
792     }
793   }
794 }