7aa665f1da32f24203694f34a4743821c1e02021
[jalview.git] / test / jalview / viewmodel / OverviewDimensionsTest.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.viewmodel;
22
23 import static org.testng.Assert.assertEquals;
24
25 import jalview.analysis.AlignmentGenerator;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.ColumnSelection;
29 import jalview.datamodel.Sequence;
30 import jalview.datamodel.SequenceCollectionI;
31 import jalview.datamodel.SequenceGroup;
32 import jalview.datamodel.SequenceI;
33
34 import java.util.Hashtable;
35
36 import org.testng.annotations.AfterClass;
37 import org.testng.annotations.BeforeClass;
38 import org.testng.annotations.BeforeMethod;
39 import org.testng.annotations.Test;
40
41 @Test(singleThreaded = true)
42 public class OverviewDimensionsTest
43 {
44   AlignmentI al;
45   OverviewDimensions od;
46
47   // cached widths and heights
48   int boxWidth;
49   int boxHeight;
50   int viewHeight;
51   int viewWidth;
52   int alheight;
53   int alwidth;
54
55   ViewportRanges vpranges;
56
57   Hashtable<SequenceI, SequenceCollectionI> hiddenRepSequences = new Hashtable<SequenceI, SequenceCollectionI>();
58
59   ColumnSelection hiddenCols = new ColumnSelection();
60
61   @BeforeClass(alwaysRun = true)
62   public void setUpJvOptionPane()
63   {
64     // create random alignment
65     AlignmentGenerator gen = new AlignmentGenerator(false);
66     al = gen.generate(157, 525, 123, 5, 5);
67   }
68
69   @BeforeMethod(alwaysRun = true)
70   public void setUp()
71   {
72     if (!hiddenRepSequences.isEmpty())
73     {
74       al.getHiddenSequences().showAll(hiddenRepSequences);
75     }
76     hiddenCols.revealAllHiddenColumns();
77     
78     vpranges = new ViewportRanges(al);
79     vpranges.setViewportStartAndHeight(0, 18);
80     vpranges.setViewportStartAndWidth(0, 63);
81
82     viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1;
83     viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1;
84
85     ColumnSelection hiddenCols = new ColumnSelection();
86
87     od = new OverviewDimensions(vpranges, true);
88     // Initial box sizing - default path through code
89     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
90
91     mouseClick(od, 0, 0);
92     moveViewport(0, 0);
93
94     // calculate before hidden columns so we get absolute values
95     alheight = vpranges.getAbsoluteAlignmentHeight();
96     alwidth = vpranges.getAbsoluteAlignmentWidth();
97
98     boxWidth = Math.round((float) (vpranges.getEndRes()
99             - vpranges.getStartRes() + 1)
100             * od.getWidth() / alwidth);
101     boxHeight = Math.round((float) (vpranges.getEndSeq()
102             - vpranges.getStartSeq() + 1)
103             * od.getSequencesHeight() / alheight);
104   }
105
106   @AfterClass(alwaysRun = true)
107   public void cleanUp()
108   {
109     al = null;
110   }
111
112   /**
113    * Test that the OverviewDimensions constructor sets width and height
114    * correctly
115    */
116   @Test(groups = { "Functional" })
117   public void testConstructor()
118   {
119     SequenceI seqa = new Sequence("Seq1", "ABC");
120     SequenceI seqb = new Sequence("Seq2", "ABC");
121     SequenceI seqc = new Sequence("Seq3", "ABC");
122     SequenceI seqd = new Sequence("Seq4", "ABC");
123     SequenceI seqe = new Sequence("Seq5",
124             "ABCABCABCABCABCABCABCABCBACBACBACBAC");
125
126     int defaultGraphHeight = 20;
127     int maxWidth = 400;
128     int minWidth = 120;
129     int maxSeqHeight = 300;
130     int minSeqHeight = 40;
131
132     // test for alignment with width > height
133     SequenceI[] seqs1 = new SequenceI[] { seqa, seqb };
134     Alignment al1 = new Alignment(seqs1);
135     ViewportRanges props = new ViewportRanges(al1);
136
137     OverviewDimensions od = new OverviewDimensions(props, true);
138     int scaledHeight = 267;
139     assertEquals(od.getGraphHeight(), defaultGraphHeight);
140     assertEquals(od.getSequencesHeight(), scaledHeight);
141     assertEquals(od.getWidth(), maxWidth);
142     assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight);
143
144     // test for alignment with width < height
145     SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd };
146     Alignment al2 = new Alignment(seqs2);
147     props = new ViewportRanges(al2);
148
149     od = new OverviewDimensions(props, true);
150     int scaledWidth = 300;
151     assertEquals(od.getGraphHeight(), defaultGraphHeight);
152     assertEquals(od.getSequencesHeight(), maxSeqHeight);
153     assertEquals(od.getWidth(), scaledWidth);
154     assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight);
155
156     // test for alignment with width > height and sequence height scaled below
157     // min value
158     SequenceI[] seqs3 = new SequenceI[] { seqe };
159     Alignment al3 = new Alignment(seqs3);
160     props = new ViewportRanges(al3);
161
162     od = new OverviewDimensions(props, true);
163     assertEquals(od.getGraphHeight(), defaultGraphHeight);
164     assertEquals(od.getSequencesHeight(), minSeqHeight);
165     assertEquals(od.getWidth(), maxWidth);
166     assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight);
167
168     // test for alignment with width < height and width scaled below min value
169     SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa,
170         seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd };
171     Alignment al4 = new Alignment(seqs4);
172     props = new ViewportRanges(al4);
173
174     od = new OverviewDimensions(props, true);
175     assertEquals(od.getGraphHeight(), defaultGraphHeight);
176     assertEquals(od.getSequencesHeight(), maxSeqHeight);
177     assertEquals(od.getWidth(), minWidth);
178     assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight);
179
180     Alignment al5 = new Alignment(seqs4);
181     props = new ViewportRanges(al5);
182
183     od = new OverviewDimensions(props, false);
184     assertEquals(od.getGraphHeight(), 0);
185     assertEquals(od.getSequencesHeight(), maxSeqHeight);
186     assertEquals(od.getWidth(), minWidth);
187     assertEquals(od.getHeight(), maxSeqHeight);
188   }
189
190   /**
191    * Test that validation after mouse adjustments to boxX and boxY sets box
192    * dimensions and scroll values correctly, when there are no hidden rows or
193    * columns.
194    */
195   @Test(groups = { "Functional" })
196   public void testSetBoxFromMouseClick()
197   {
198     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
199             vpranges);
200     assertEquals(od.getBoxX(), 0);
201     assertEquals(od.getBoxY(), 0);
202     assertEquals(od.getBoxWidth(), boxWidth);
203     assertEquals(vpranges.getStartSeq(), 0);
204     assertEquals(vpranges.getStartSeq(), 0);
205
206     // negative boxX value reset to 0
207     mouseClick(od, -5, 10);
208     assertEquals(od.getBoxX(), 0);
209     assertEquals(od.getBoxWidth(), boxWidth);
210     assertEquals(od.getBoxHeight(), boxHeight);
211     assertEquals(vpranges.getStartSeq(),
212             Math.round((float) 10 * alheight / od.getSequencesHeight()));
213     assertEquals(vpranges.getStartRes(), 0);
214
215     // negative boxY value reset to 0
216     mouseClick(od, 6, -2);
217     assertEquals(od.getBoxY(), 0);
218     assertEquals(od.getBoxWidth(), boxWidth);
219     assertEquals(od.getBoxHeight(), boxHeight);
220     assertEquals(vpranges.getStartRes(),
221             Math.round((float) 6 * alwidth / od.getWidth()));
222     assertEquals(vpranges.getStartSeq(), 0);
223
224     // overly large boxX value reset to width-boxWidth
225     mouseClick(od, 100, 6);
226     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
227     assertEquals(od.getBoxY(), 6);
228     assertEquals(od.getBoxWidth(), boxWidth);
229     assertEquals(od.getBoxHeight(), boxHeight);
230     assertEquals(vpranges.getStartRes(),
231             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
232     assertEquals(
233             vpranges.getStartSeq(),
234             Math.round((float) od.getBoxY() * alheight
235                     / od.getSequencesHeight()));
236
237     // overly large boxY value reset to sequenceHeight - boxHeight
238     mouseClick(od, 10, 520);
239     assertEquals(od.getBoxX(), 10);
240     assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight());
241     assertEquals(od.getBoxWidth(), boxWidth);
242     assertEquals(od.getBoxHeight(), boxHeight);
243     assertEquals(vpranges.getStartRes(),
244             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
245
246     // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5
247     // and round rounds to 508; however we get 507 working with row values
248     // hence the subtraction of 1
249     assertEquals(
250             vpranges.getStartSeq(),
251             Math.round((float) od.getBoxY() * alheight
252                     / od.getSequencesHeight()) - 1);
253
254     // click past end of alignment, as above
255     mouseClick(od, 3000, 5);
256     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
257     assertEquals(od.getBoxWidth(), boxWidth);
258     assertEquals(od.getBoxHeight(), boxHeight);
259     assertEquals(vpranges.getStartRes(),
260             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
261     assertEquals(
262             vpranges.getStartSeq(),
263             Math.round((float) od.getBoxY() * alheight
264                     / od.getSequencesHeight()));
265
266     // move viewport so startRes non-zero and then mouseclick
267     moveViewportH(50);
268
269     // click at viewport position
270     int oldboxx = od.getBoxX();
271     int oldboxy = od.getBoxY();
272     mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2);
273     assertEquals(od.getBoxX(), oldboxx + 5);
274     assertEquals(od.getBoxWidth(), boxWidth);
275     assertEquals(od.getBoxHeight(), boxHeight);
276     assertEquals(vpranges.getStartRes(),
277             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
278     assertEquals(od.getBoxY(), oldboxy + 2);
279     assertEquals(
280             vpranges.getStartSeq(),
281             Math.round((float) od.getBoxY() * alheight
282                     / od.getSequencesHeight()));
283
284     // click at top corner
285     mouseClick(od, 0, 0);
286     assertEquals(od.getBoxX(), 0);
287     assertEquals(vpranges.getStartRes(), 0);
288     assertEquals(od.getBoxY(), 0);
289     assertEquals(vpranges.getStartSeq(), 0);
290     assertEquals(od.getBoxWidth(), boxWidth);
291     assertEquals(od.getBoxHeight(), boxHeight);
292   }
293
294   /**
295    * Test setting of the box position, when there are hidden cols at the start
296    * of the alignment
297    */
298   @Test(groups = { "Functional" })
299   public void testFromMouseWithHiddenColsAtStart()
300   {
301     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
302             vpranges);
303     assertEquals(od.getBoxX(), 0);
304     assertEquals(od.getBoxY(), 0);
305     assertEquals(od.getBoxWidth(), boxWidth);
306     assertEquals(vpranges.getStartRes(), 0);
307     assertEquals(vpranges.getStartSeq(), 0);
308
309     // hide cols at start and check updated box position is correct
310     // changes boxX but not boxwidth
311     int lastHiddenCol = 30;
312     hiddenCols.hideColumns(0, lastHiddenCol);
313
314     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
315     assertEquals(od.getBoxX(),
316             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
317                     / alwidth));
318     assertEquals(od.getBoxWidth(), boxWidth);
319     assertEquals(od.getBoxHeight(), boxHeight);
320
321     // try to click in hidden cols, check box does not move
322     int xpos = 10;
323     mouseClick(od, xpos, 0);
324     assertEquals(
325             od.getBoxX(),
326             Math.round((float) (lastHiddenCol + 1) * od.getWidth()
327                     / alwidth));
328     assertEquals(od.getBoxY(), 0);
329     assertEquals(od.getBoxWidth(), boxWidth);
330     assertEquals(od.getBoxHeight(), boxHeight);
331     assertEquals(vpranges.getStartSeq(), 0);
332     assertEquals(vpranges.getStartRes(), 0);
333
334     // click to right of hidden columns, box moves to click point
335     testBoxIsAtClickPoint(40, 0);
336     assertEquals(vpranges.getStartSeq(), 0);
337     assertEquals(vpranges.getStartRes(),
338             Math.round((float) 40 * alwidth / od.getWidth())
339                     - (lastHiddenCol + 1));
340
341     // click to right of hidden columns such that box runs over right hand side
342     // of alignment
343     // box position is adjusted away from the edge
344     // overly large boxX value reset to width-boxWidth
345     xpos = 100;
346     mouseClick(od, xpos, 5);
347     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
348     assertEquals(od.getBoxY(), 5);
349     assertEquals(od.getBoxWidth(), boxWidth);
350     assertEquals(od.getBoxHeight(), boxHeight);
351     assertEquals(vpranges.getStartRes(),
352             Math.round((float) od.getBoxX() * alwidth / od.getWidth())
353                     - (lastHiddenCol + 1));
354     assertEquals(
355             vpranges.getStartSeq(),
356             Math.round((float) od.getBoxY() * alheight
357                     / od.getSequencesHeight()));
358   }
359
360   /**
361    * Test setting of the box position, when there are hidden cols in the middle
362    * of the alignment
363    */
364   @Test(groups = { "Functional" })
365   public void testFromMouseWithHiddenColsInMiddle()
366   {
367     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
368             vpranges);
369     assertEquals(od.getBoxX(), 0);
370     assertEquals(od.getBoxY(), 0);
371     assertEquals(od.getBoxWidth(), boxWidth);
372     assertEquals(vpranges.getStartRes(), 0);
373     assertEquals(vpranges.getStartSeq(), 0);
374     
375     // hide columns 63-73, no change to box position or dimensions
376     int firstHidden = 63;
377     int lastHidden = 73;
378     hiddenCols.hideColumns(firstHidden, lastHidden);
379
380     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
381     assertEquals(od.getBoxX(), 0);
382     assertEquals(od.getBoxY(), 0);
383     assertEquals(od.getBoxWidth(), boxWidth);
384     assertEquals(vpranges.getStartRes(), 0);
385     assertEquals(vpranges.getStartSeq(), 0);
386
387     // move box so that it overlaps with hidden cols on one side
388     // box width changes, boxX and scrollCol as for unhidden case
389     int xpos = 55 - boxWidth; // 55 is position in overview approx halfway
390                               // between cols 60 and 70
391     mouseClick(od, xpos, 0);
392     assertEquals(od.getBoxX(), xpos);
393     assertEquals(od.getBoxY(), 0);
394     assertEquals(
395             od.getBoxWidth(),
396             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
397                     * od.getWidth() / alwidth));
398     assertEquals(od.getBoxHeight(), boxHeight);
399     assertEquals(vpranges.getStartRes(),
400             Math.round(xpos * alwidth / od.getWidth()));
401     assertEquals(vpranges.getStartSeq(), 0);
402
403     // move box so that it completely covers hidden cols
404     // box width changes, boxX and scrollCol as for hidden case
405     xpos = 33;
406     mouseClick(od, xpos, 0);
407     assertEquals(od.getBoxX(), xpos);
408     assertEquals(od.getBoxY(), 0);
409     assertEquals(
410             od.getBoxWidth(),
411             Math.round(boxWidth + (float) (lastHidden - firstHidden + 1)
412                     * od.getWidth() / alwidth));
413     assertEquals(od.getBoxHeight(), boxHeight);
414     assertEquals(vpranges.getStartRes(),
415             Math.round((float) xpos * alwidth / od.getWidth()));
416     assertEquals(vpranges.getStartSeq(), 0);
417
418     // move box so boxX is in hidden cols, box overhangs at right
419     // boxX and scrollCol at left of hidden area, box width extends across
420     // hidden region
421     xpos = 50;
422     mouseClick(od, xpos, 0);
423     assertEquals(od.getBoxX(),
424             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth));
425     assertEquals(od.getBoxY(), 0);
426     assertEquals(
427             od.getBoxWidth(),
428             boxWidth
429                     + Math.round((float) (lastHidden - firstHidden + 1)
430                             * od.getWidth() / alwidth));
431     assertEquals(od.getBoxHeight(), boxHeight);
432     assertEquals(vpranges.getStartRes(), firstHidden - 1);
433     assertEquals(vpranges.getStartSeq(), 0);
434
435     // move box so boxX is to right of hidden cols, but does not go beyond full
436     // width of alignment
437     // box width, boxX and scrollCol all as for non-hidden case
438     xpos = 75;
439     testBoxIsAtClickPoint(xpos, 0);
440     assertEquals(vpranges.getStartSeq(), 0);
441     assertEquals(vpranges.getStartRes(),
442             Math.round(xpos * alwidth / od.getWidth())
443                     - (lastHidden - firstHidden + 1));
444     
445     // move box so it goes beyond full width of alignment
446     // boxX, scrollCol adjusted back, box width normal
447     xpos = 3000;
448     mouseClick(od, xpos, 5);
449     assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth());
450     assertEquals(od.getBoxY(), 5);
451     assertEquals(od.getBoxWidth(), boxWidth);
452     assertEquals(od.getBoxHeight(), boxHeight);
453     assertEquals(
454             vpranges.getStartRes(),
455             Math.round(((float) od.getBoxX() * alwidth / od.getWidth())
456                     - (lastHidden - firstHidden + 1)));
457     assertEquals(
458             vpranges.getStartSeq(),
459             Math.round((float) od.getBoxY() * alheight
460                     / od.getSequencesHeight()));
461
462   }
463
464   /**
465    * Test setting of the box position, when there are hidden cols at the end of
466    * the alignment
467    */
468   @Test(groups = { "Functional" })
469   public void testFromMouseWithHiddenColsAtEnd()
470   {
471     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
472             vpranges);
473     assertEquals(od.getBoxX(), 0);
474     assertEquals(od.getBoxY(), 0);
475     assertEquals(od.getBoxWidth(), boxWidth);
476     assertEquals(vpranges.getStartRes(), 0);
477     assertEquals(vpranges.getStartSeq(), 0);
478
479     // hide columns 140-164, no change to box position or dimensions
480     int firstHidden = 140;
481     int lastHidden = 164;
482     hiddenCols.hideColumns(firstHidden, lastHidden);
483     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
484     assertEquals(od.getBoxX(), 0);
485     assertEquals(od.getBoxY(), 0);
486     assertEquals(od.getBoxWidth(), boxWidth);
487     assertEquals(vpranges.getStartRes(), 0);
488     assertEquals(vpranges.getStartSeq(), 0);
489
490     // click to left of hidden cols, without overlapping
491     // boxX, scrollCol and width as normal
492     int xpos = 5;
493     testBoxIsAtClickPoint(xpos, 0);
494     assertEquals(vpranges.getStartSeq(), 0);
495     assertEquals(vpranges.getStartRes(),
496             Math.round((float) xpos * alwidth / od.getWidth()));
497
498     // click to left of hidden cols, with overlap
499     // boxX and scrollCol adjusted for hidden cols, width normal
500     xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth;
501     mouseClick(od, xpos, 0);
502     assertEquals(od.getBoxX(),
503             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
504                     - boxWidth + 1);
505     assertEquals(od.getBoxY(), 0);
506     assertEquals(od.getBoxWidth(), boxWidth);
507     assertEquals(od.getBoxHeight(), boxHeight);
508     assertEquals(vpranges.getStartRes(),
509             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
510     assertEquals(vpranges.getStartSeq(), 0);
511
512     // click in hidden cols
513     // boxX and scrollCol adjusted for hidden cols, width normal
514     xpos = 115;
515     assertEquals(od.getBoxX(),
516             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
517                     - boxWidth + 1);
518     assertEquals(od.getBoxY(), 0);
519     assertEquals(od.getBoxWidth(), boxWidth);
520     assertEquals(od.getBoxHeight(), boxHeight);
521     assertEquals(vpranges.getStartRes(),
522             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
523     assertEquals(vpranges.getStartSeq(), 0);
524
525     // click off end of alignment
526     // boxX and scrollCol adjusted for hidden cols, width normal
527     xpos = 3000;
528     assertEquals(od.getBoxX(),
529             Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)
530                     - boxWidth + 1);
531     assertEquals(od.getBoxY(), 0);
532     assertEquals(od.getBoxWidth(), boxWidth);
533     assertEquals(od.getBoxHeight(), boxHeight);
534     assertEquals(vpranges.getStartRes(),
535             Math.round((float) od.getBoxX() * alwidth / od.getWidth()));
536     assertEquals(vpranges.getStartSeq(), 0);
537   }
538
539   /**
540    * Test that the box position is set correctly when set from the viewport,
541    * with no hidden rows or columns
542    */
543   @Test(groups = { "Functional" })
544   public void testSetBoxFromViewport()
545   {
546     // move viewport to start of alignment
547     moveViewport(0, 0);
548     assertEquals(od.getBoxX(), 0);
549     assertEquals(od.getBoxY(), 0);
550     assertEquals(od.getBoxWidth(), boxWidth);
551     assertEquals(od.getBoxHeight(), boxHeight);
552
553     // move viewport to right
554     moveViewportH(70);
555     assertEquals(od.getBoxX(),
556             Math.round((float) 70 * od.getWidth() / alwidth));
557     assertEquals(od.getBoxY(), 0);
558     assertEquals(od.getBoxWidth(), boxWidth);
559     assertEquals(od.getBoxHeight(), boxHeight);
560
561     // move viewport down
562     moveViewportV(100);
563     assertEquals(od.getBoxX(),
564             Math.round((float) 70 * od.getWidth() / alwidth));
565     assertEquals(od.getBoxY(),
566             Math.round(100 * od.getSequencesHeight() / alheight));
567     assertEquals(od.getBoxWidth(), boxWidth);
568     assertEquals(od.getBoxHeight(), boxHeight);
569
570     // move viewport to bottom right
571     moveViewport(98, 507);
572     assertEquals(od.getBoxX(),
573             Math.round((float) 98 * od.getWidth() / alwidth));
574     assertEquals(od.getBoxY(),
575             Math.round((float) 507 * od.getSequencesHeight() / alheight));
576     assertEquals(od.getBoxWidth(), boxWidth);
577     assertEquals(od.getBoxHeight(), boxHeight);
578   }
579
580   /**
581    * Test that the box position is set correctly when there are hidden columns
582    * at the start
583    */
584   @Test(groups = { "Functional" })
585   public void testSetBoxFromViewportHiddenColsAtStart()
586   {
587     int firstHidden = 0;
588     int lastHidden = 20;
589     hiddenCols.hideColumns(firstHidden, lastHidden);
590
591     // move viewport to start of alignment
592     moveViewport(0, 0);
593     assertEquals(od.getBoxX(),
594             Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth));
595     assertEquals(od.getBoxY(), 0);
596     assertEquals(od.getBoxWidth(), boxWidth);
597     assertEquals(od.getBoxHeight(), boxHeight);
598
599     // move viewport to end of alignment - need to make startRes by removing
600     // hidden cols because of how viewport/overview are implemented
601     moveViewport(98 - lastHidden - 1, 0);
602     assertEquals(od.getBoxX(),
603             Math.round((float) 98 * od.getWidth() / alwidth));
604     assertEquals(od.getBoxY(), 0);
605     assertEquals(od.getBoxWidth(), boxWidth);
606     assertEquals(od.getBoxHeight(), boxHeight);
607   }
608
609   /**
610    * Test that the box position is set correctly when there are hidden columns
611    * in the middle
612    */
613   @Test(groups = { "Functional" })
614   public void testSetBoxFromViewportHiddenColsInMiddle()
615   {
616     int firstHidden = 68;
617     int lastHidden = 78;
618     hiddenCols.hideColumns(firstHidden, lastHidden);
619
620     // move viewport before hidden columns
621     moveViewport(3, 0);
622
623     assertEquals(od.getBoxX(),
624             Math.round((float) 3 * od.getWidth() / alwidth));
625     assertEquals(od.getBoxY(), 0);
626     System.out.println(od.getBoxWidth());
627     assertEquals(od.getBoxWidth(), boxWidth);
628     System.out.println(od.getBoxWidth());
629     assertEquals(od.getBoxHeight(), boxHeight);
630
631     // move viewport to left of hidden columns with overlap
632     moveViewport(10, 0);
633     assertEquals(od.getBoxX(),
634             Math.round((float) 10 * od.getWidth() / alwidth));
635     assertEquals(od.getBoxY(), 0);
636     assertEquals(
637             od.getBoxWidth(),
638             boxWidth
639                     + Math.round((float) (lastHidden - firstHidden + 1)
640                             * od.getWidth() / alwidth));
641     assertEquals(od.getBoxHeight(), boxHeight);
642
643     // move viewport to straddle hidden columns
644     moveViewport(63, 0);
645     assertEquals(od.getBoxX(),
646             Math.round((float) 63 * od.getWidth() / alwidth));
647     assertEquals(od.getBoxY(), 0);
648     assertEquals(
649             od.getBoxWidth(),
650             boxWidth
651                     + Math.round((lastHidden - firstHidden + 1)
652                             * od.getWidth() / alwidth));
653     assertEquals(od.getBoxHeight(), boxHeight);
654
655     // move viewport to right of hidden columns, no overlap
656     moveViewport(80 - (lastHidden - firstHidden + 1), 0);
657     assertEquals(od.getBoxX(),
658             Math.round((float) 80 * od.getWidth() / alwidth));
659     assertEquals(od.getBoxY(), 0);
660     assertEquals(od.getBoxWidth(), boxWidth);
661     assertEquals(od.getBoxHeight(), boxHeight);
662
663   }
664
665   /**
666    * Test that the box position is set correctly when there are hidden columns
667    * at the end
668    */
669   @Test(groups = { "Functional" })
670   public void testSetBoxFromViewportHiddenColsAtEnd()
671   {
672     int firstHidden = 152;
673     int lastHidden = 164;
674     hiddenCols.hideColumns(firstHidden, lastHidden);
675
676     // move viewport before hidden columns
677     moveViewport(3, 0);
678     assertEquals(od.getBoxX(),
679             Math.round((float) 3 * od.getWidth() / alwidth));
680     assertEquals(od.getBoxY(), 0);
681     assertEquals(od.getBoxWidth(), boxWidth);
682     assertEquals(od.getBoxHeight(), boxHeight);
683
684     // move viewport to hidden columns
685     // viewport can't actually extend into hidden cols,
686     // so move to the far right edge of the viewport
687     moveViewport(firstHidden - viewWidth, 0);
688     assertEquals(od.getBoxX(),
689             Math.round((float) (firstHidden - viewWidth)
690                     * od.getWidth() / alwidth));
691     assertEquals(od.getBoxY(), 0);
692     assertEquals(od.getBoxWidth(), boxWidth);
693     assertEquals(od.getBoxHeight(), boxHeight);
694   }
695
696   /**
697    * Test that the box position is set correctly when there are hidden rows at
698    * the start
699    */
700   @Test(groups = { "Functional" })
701   public void testSetBoxFromViewportHiddenRowsAtStart()
702   {
703     int firstHidden = 0;
704     int lastHidden = 20;
705     hideSequences(firstHidden, lastHidden);
706
707     // move viewport to start of alignment:
708     // box moves to below hidden rows, height remains same
709     moveViewport(0, 0);
710     assertEquals(od.getBoxX(), 0);
711     assertEquals(od.getBoxY(),
712             Math.round((float) (lastHidden + 1) * od.getSequencesHeight()
713                     / alheight));
714     assertEquals(od.getBoxWidth(), boxWidth);
715     assertEquals(od.getBoxHeight(), boxHeight);
716
717     // move viewport to end of alignment
718     moveViewport(0, 525 - viewHeight - lastHidden - 1);
719     assertEquals(od.getBoxX(), 0);
720     assertEquals(
721             od.getBoxY(),
722             Math.round((float) (525 - viewHeight) * od.getSequencesHeight()
723                     / alheight));
724     assertEquals(od.getBoxWidth(), boxWidth);
725     assertEquals(od.getBoxHeight(), boxHeight);
726   }
727
728   /**
729    * Test that the box position is set correctly when there are hidden rows in
730    * the middle
731    */
732   @Test(groups = { "Functional" })
733   public void testSetBoxFromViewportHiddenRowsInMiddle()
734   {
735     int firstHidden = 200;
736     int lastHidden = 210;
737     hideSequences(firstHidden, lastHidden);
738
739     // move viewport to start of alignment:
740     // box, height etc as in non-hidden case
741     moveViewport(0, 0);
742     assertEquals(od.getBoxX(), 0);
743     assertEquals(od.getBoxY(), 0);
744     assertEquals(od.getBoxWidth(), boxWidth);
745     assertEquals(od.getBoxHeight(), boxHeight);
746
747     // move viewport to straddle hidden rows
748     moveViewport(0, 198);
749     assertEquals(od.getBoxX(), 0);
750     assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight()
751             / alheight));
752     assertEquals(od.getBoxWidth(), boxWidth);
753     assertEquals(
754             od.getBoxHeight(),
755             Math.round((float) (viewHeight + lastHidden - firstHidden + 1)
756                     * od.getSequencesHeight() / alheight));
757   }
758
759   /**
760    * Test that the box position is set correctly when there are hidden rows at
761    * the bottom
762    */
763   @Test(groups = { "Functional" })
764   public void testSetBoxFromViewportHiddenRowsAtEnd()
765   {
766     int firstHidden = 500;
767     int lastHidden = 524;
768     hideSequences(firstHidden, lastHidden);
769
770     // move viewport to start of alignment:
771     // box, height etc as in non-hidden case
772     moveViewport(0, 0);
773     assertEquals(od.getBoxX(), 0);
774     assertEquals(od.getBoxY(), 0);
775     assertEquals(od.getBoxWidth(), boxWidth);
776     assertEquals(od.getBoxHeight(), boxHeight);
777
778     // move viewport to end of alignment
779     // viewport sits above hidden rows and does not include them
780     moveViewport(0, firstHidden - viewHeight - 1);
781     assertEquals(od.getBoxX(), 0);
782     assertEquals(
783             od.getBoxY(),
784             Math.round((float) (firstHidden - viewHeight - 1)
785                     * od.getSequencesHeight() / alheight));
786     assertEquals(od.getBoxWidth(), boxWidth);
787     assertEquals(od.getBoxHeight(), boxHeight);
788
789   }
790
791   /**
792    * Test setting of the box position, when there are hidden rows at the start
793    * of the alignment
794    */
795   @Test(groups = { "Functional" })
796   public void testFromMouseWithHiddenRowsAtStart()
797   {
798     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
799             vpranges);
800     assertEquals(od.getBoxX(), 0);
801     assertEquals(od.getBoxY(), 0);
802     assertEquals(od.getBoxHeight(), boxHeight);
803     assertEquals(od.getBoxWidth(), boxWidth);
804     assertEquals(vpranges.getStartRes(), 0);
805     assertEquals(vpranges.getStartSeq(), 0);
806
807     // hide rows at start and check updated box position is correct
808     // changes boxY but not boxheight
809     int lastHiddenRow = 30;
810     hideSequences(0, lastHiddenRow);
811
812     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
813     assertEquals(od.getBoxX(), 0);
814     assertEquals(od.getBoxY(),
815             Math.round((float) (lastHiddenRow + 1)
816                     * od.getSequencesHeight() / alheight));
817     assertEquals(od.getBoxWidth(), boxWidth);
818     assertEquals(od.getBoxHeight(), boxHeight);
819
820     // click in hidden rows - same result
821     mouseClick(od, 0, 0);
822     assertEquals(od.getBoxX(), 0);
823     assertEquals(
824             od.getBoxY(),
825             Math.round((float) (lastHiddenRow + 1)
826                     * od.getSequencesHeight() / alheight));
827     assertEquals(od.getBoxWidth(), boxWidth);
828     assertEquals(od.getBoxHeight(), boxHeight);
829
830     // click below hidden rows
831     mouseClick(od, 0, 150);
832     assertEquals(od.getBoxX(), 0);
833     assertEquals(od.getBoxY(), 150);
834     assertEquals(od.getBoxWidth(), boxWidth);
835     assertEquals(od.getBoxHeight(), boxHeight);
836   }
837
838   /**
839    * Test setting of the box position, when there are hidden rows at the middle
840    * of the alignment
841    */
842   @Test(groups = { "Functional" })
843   public void testFromMouseWithHiddenRowsInMiddle()
844   {
845     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
846             vpranges);
847
848     assertEquals(od.getBoxX(), 0);
849     assertEquals(od.getBoxY(), 0);
850     assertEquals(od.getBoxWidth(), boxWidth);
851     assertEquals(od.getBoxHeight(), boxHeight);
852     assertEquals(vpranges.getStartRes(), 0);
853     assertEquals(vpranges.getStartSeq(), 0);
854
855     // hide rows in middle and check updated box position is correct
856     // no changes
857     int firstHiddenRow = 50;
858     int lastHiddenRow = 54;
859     hideSequences(firstHiddenRow, lastHiddenRow);
860
861     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
862
863     assertEquals(od.getBoxX(), 0);
864     assertEquals(od.getBoxY(), 0);
865     assertEquals(od.getBoxWidth(), boxWidth);
866     assertEquals(od.getBoxHeight(), boxHeight);
867
868     // click above hidden rows, so that box overlaps
869     int ypos = 35; // column value in residues
870     mouseClick(od, 0,
871             Math.round((float) ypos * od.getSequencesHeight() / alheight));
872     assertEquals(od.getBoxX(), 0);
873     assertEquals(od.getBoxY(),
874             Math.round((float) ypos * od.getSequencesHeight() / alheight));
875     assertEquals(od.getBoxWidth(), boxWidth);
876     assertEquals(
877             od.getBoxHeight(),
878             boxHeight
879                     + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
880                             * od.getSequencesHeight() / alheight));
881
882     // click so that box straddles hidden rows
883     ypos = 44; // column value in residues
884     mouseClick(od, 0,
885             Math.round((float) ypos * od.getSequencesHeight() / alheight));
886     assertEquals(od.getBoxX(), 0);
887     assertEquals(od.getBoxY(),
888             Math.round((float) ypos * od.getSequencesHeight() / alheight));
889     assertEquals(od.getBoxWidth(), boxWidth);
890     assertEquals(
891             od.getBoxHeight(),
892             boxHeight
893                     + Math.round((float) (lastHiddenRow - firstHiddenRow + 1)
894                             * od.getSequencesHeight() / alheight));
895   }
896
897   /**
898    * Test setting of the box position, when there are hidden rows at the end of
899    * the alignment
900    */
901   @Test(groups = { "Functional" })
902   public void testFromMouseWithHiddenRowsAtEnd()
903   {
904     od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols,
905             vpranges);
906     assertEquals(od.getBoxX(), 0);
907     assertEquals(od.getBoxY(), 0);
908     assertEquals(od.getBoxWidth(), boxWidth);
909     assertEquals(od.getBoxHeight(), boxHeight);
910     assertEquals(vpranges.getStartRes(), 0);
911     assertEquals(vpranges.getStartSeq(), 0);
912
913     // hide rows at end and check updated box position is correct
914     // no changes
915     int firstHidden = 500;
916     int lastHidden = 524;
917     hideSequences(firstHidden, lastHidden);
918
919     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
920     assertEquals(od.getBoxX(), 0);
921     assertEquals(od.getBoxY(), 0);
922     assertEquals(od.getBoxWidth(), boxWidth);
923     assertEquals(od.getBoxHeight(), boxHeight);
924
925     // click above hidden rows
926     int ypos = 40; // row 40
927     mouseClick(od, 0,
928             Math.round((float) ypos * od.getSequencesHeight() / alheight));
929     assertEquals(od.getBoxX(), 0);
930     assertEquals(od.getBoxY(),
931             Math.round((float) ypos * od.getSequencesHeight() / alheight));
932     assertEquals(od.getBoxWidth(), boxWidth);
933     assertEquals(od.getBoxHeight(), boxHeight);
934
935     // click above hidden rows so box overlaps
936     // boxY moved upwards, boxHeight remains same
937     ypos = 497; // row 497
938     mouseClick(od, 0,
939             Math.round((float) ypos * od.getSequencesHeight() / alheight));
940     assertEquals(od.getBoxX(), 0);
941     assertEquals(
942             od.getBoxY(),
943             Math.round((float) (firstHidden - viewHeight)
944                     * od.getSequencesHeight() / alheight));
945     assertEquals(od.getBoxWidth(), boxWidth);
946     assertEquals(od.getBoxHeight(), boxHeight);
947
948     // click within hidden rows
949     ypos = 505;
950     mouseClick(od, 0,
951             Math.round((float) ypos * od.getSequencesHeight() / alheight));
952     assertEquals(od.getBoxX(), 0);
953     assertEquals(
954             od.getBoxY(),
955             Math.round((firstHidden - viewHeight) * od.getSequencesHeight()
956                     / alheight));
957     assertEquals(od.getBoxWidth(), boxWidth);
958     assertEquals(od.getBoxHeight(), boxHeight);
959   }
960
961   /*
962    * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same.
963    */
964   private void moveViewportH(int startRes)
965   {
966     vpranges.setViewportStartAndWidth(startRes, viewWidth);
967     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
968   }
969
970   /*
971    * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same.
972    */
973   private void moveViewportV(int startSeq)
974   {
975     vpranges.setViewportStartAndHeight(startSeq, viewHeight);
976     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
977   }
978
979   /*
980    * Move viewport horizontally and vertically.
981    */
982   private void moveViewport(int startRes, int startSeq)
983   {
984     vpranges.setViewportStartAndWidth(startRes, viewWidth);
985     vpranges.setViewportStartAndHeight(startSeq, viewHeight);
986     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
987   }
988
989   /*
990    * Mouse click as position x,y in overview window
991    */
992   private void mouseClick(OverviewDimensions od, int x, int y)
993   {
994     od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols,
995             vpranges);
996
997     // updates require an OverviewPanel to exist which it doesn't here
998     // so call setBoxPosition() as it would be called by the AlignmentPanel
999     // normally
1000     od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges);
1001   }
1002   
1003   /*
1004    * Test that the box is positioned with the top left corner at xpos, ypos
1005    * and with the original width and height
1006    */
1007   private void testBoxIsAtClickPoint(int xpos, int ypos)
1008   {
1009     mouseClick(od, xpos, ypos);
1010     assertEquals(od.getBoxX(), xpos);
1011     assertEquals(od.getBoxY(), ypos);
1012     assertEquals(od.getBoxWidth(), boxWidth);
1013     assertEquals(od.getBoxHeight(), boxHeight);
1014
1015   }
1016
1017   /*
1018    * Hide sequences between start and end
1019    */
1020   private void hideSequences(int start, int end)
1021   {
1022     SequenceI[] allseqs = al.getSequencesArray();
1023     SequenceGroup theseSeqs = new SequenceGroup();
1024     
1025     for (int i = start; i <= end; i++)
1026     {
1027       theseSeqs.addSequence(allseqs[i], false);
1028       al.getHiddenSequences().hideSequence(allseqs[i]);
1029     }
1030
1031     hiddenRepSequences.put(allseqs[start], theseSeqs);
1032   }
1033 }