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