From: kiramt Date: Wed, 22 Mar 2017 13:53:57 +0000 (+0000) Subject: Merge remote-tracking branch X-Git-Tag: Release_2_10_2~3^2~149 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=ef0a35a8dff8c0cc6ffa634c2b01cdca61f74b3d;hp=9d40dad63906695a693c749f9c95377491eb71bd;p=jalview.git Merge remote-tracking branch 'origin/bug/JAL-2436featureRendererThreading' into develop Conflicts: src/jalview/appletgui/OverviewPanel.java src/jalview/gui/OverviewPanel.java --- diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index ffa413b..ee16f94 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -291,7 +291,7 @@ public class AAFrequency /** * Derive the gap count annotation row. * - * @param consensus + * @param gaprow * the annotation row to add annotations to * @param profiles * the source consensus data @@ -300,11 +300,11 @@ public class AAFrequency * @param endCol * end column (exclusive) */ - public static void completeGapAnnot(AlignmentAnnotation consensus, + public static void completeGapAnnot(AlignmentAnnotation gaprow, ProfilesI profiles, int startCol, int endCol, long nseq) { - if (consensus == null || consensus.annotations == null - || consensus.annotations.length < endCol) + if (gaprow == null || gaprow.annotations == null + || gaprow.annotations.length < endCol) { /* * called with a bad alignment annotation row @@ -313,8 +313,8 @@ public class AAFrequency return; } // always set ranges again - consensus.graphMax = nseq; - consensus.graphMin = 0; + gaprow.graphMax = nseq; + gaprow.graphMin = 0; for (int i = startCol; i < endCol; i++) { ProfileI profile = profiles.get(i); @@ -324,7 +324,7 @@ public class AAFrequency * happens if sequences calculated over were * shorter than alignment width */ - consensus.annotations[i] = null; + gaprow.annotations[i] = null; return; } @@ -332,7 +332,7 @@ public class AAFrequency String description = String.valueOf(gapped); - consensus.annotations[i] = new Annotation(description, description, + gaprow.annotations[i] = new Annotation(description, description, '\0', gapped); } diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index 634521c..8b07340 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -33,6 +33,7 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; +import jalview.viewmodel.ViewportRanges; import java.awt.Color; import java.util.Hashtable; @@ -46,7 +47,13 @@ import java.util.Map; public interface AlignViewportI extends ViewStyleI { - int getEndRes(); + /** + * Get the ranges object containing details of the start and end sequences and + * residues + * + * @return + */ + public ViewportRanges getRanges(); /** * calculate the height for visible annotation, revalidating bounds where diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index 6a0b390..e51131b 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -75,6 +75,7 @@ import jalview.structures.models.AAStructureBindingModel; import jalview.util.MappingUtils; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import java.awt.BorderLayout; import java.awt.Canvas; @@ -420,6 +421,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, @Override public void keyPressed(KeyEvent evt) { + ViewportRanges ranges = viewport.getRanges(); + if (viewport.cursorMode && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt @@ -571,8 +574,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, new String[] { (viewport.cursorMode ? "on" : "off") })); if (viewport.cursorMode) { - alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes; - alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq; + alignPanel.seqPanel.seqCanvas.cursorX = ranges.getStartRes(); + alignPanel.seqPanel.seqCanvas.cursorY = ranges.getStartSeq(); } break; @@ -598,8 +601,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } else { - alignPanel.setScrollValues(viewport.startRes, viewport.startSeq - - viewport.endSeq + viewport.startSeq); + alignPanel.setScrollValues(ranges.getStartRes(), + 2 * ranges.getStartSeq() - ranges.getEndSeq()); } break; @@ -610,8 +613,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } else { - alignPanel.setScrollValues(viewport.startRes, viewport.startSeq - + viewport.endSeq - viewport.startSeq); + alignPanel + .setScrollValues(ranges.getStartRes(), ranges.getEndSeq()); } break; @@ -2063,7 +2066,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, seqs, 0, viewport.getAlignment().getWidth(), viewport.getAlignment())); - viewport.setEndSeq(viewport.getAlignment().getHeight()); + viewport.getRanges().setEndSeq(viewport.getAlignment().getHeight()); viewport.getAlignment().getWidth(); viewport.firePropertyChange("alignment", null, viewport.getAlignment() .getSequences()); @@ -2299,6 +2302,8 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, void trimAlignment(boolean trimLeft) { + AlignmentI al = viewport.getAlignment(); + ViewportRanges ranges = viewport.getRanges(); ColumnSelection colSel = viewport.getColumnSelection(); int column; @@ -2321,20 +2326,20 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } else { - seqs = viewport.getAlignment().getSequencesArray(); + seqs = al.getSequencesArray(); } TrimRegionCommand trimRegion; if (trimLeft) { trimRegion = new TrimRegionCommand("Remove Left", true, seqs, - column, viewport.getAlignment()); - viewport.setStartRes(0); + column, al); + ranges.setStartRes(0); } else { trimRegion = new TrimRegionCommand("Remove Right", false, seqs, - column, viewport.getAlignment()); + column, al); } statusBar.setText(MessageManager.formatMessage( @@ -2343,23 +2348,25 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, .toString() })); addHistoryItem(trimRegion); - for (SequenceGroup sg : viewport.getAlignment().getGroups()) + for (SequenceGroup sg : al.getGroups()) { if ((trimLeft && !sg.adjustForRemoveLeft(column)) || (!trimLeft && !sg.adjustForRemoveRight(column))) { - viewport.getAlignment().deleteGroup(sg); + al.deleteGroup(sg); } } - viewport.firePropertyChange("alignment", null, viewport - .getAlignment().getSequences()); + viewport.firePropertyChange("alignment", null, al.getSequences()); } } public void removeGappedColumnMenuItem_actionPerformed() { - int start = 0, end = viewport.getAlignment().getWidth() - 1; + AlignmentI al = viewport.getAlignment(); + ViewportRanges ranges = viewport.getRanges(); + int start = 0; + int end = ranges.getAbsoluteAlignmentWidth() - 1; SequenceI[] seqs; if (viewport.getSelectionGroup() != null) @@ -2387,22 +2394,24 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, // This is to maintain viewport position on first residue // of first sequence - SequenceI seq = viewport.getAlignment().getSequenceAt(0); - int startRes = seq.findPosition(viewport.startRes); + SequenceI seq = al.getSequenceAt(0); + int startRes = seq.findPosition(ranges.getStartRes()); // ShiftList shifts; // viewport.getAlignment().removeGaps(shifts=new ShiftList()); // edit.alColumnChanges=shifts.getInverse(); // if (viewport.hasHiddenColumns) // viewport.getColumnSelection().compensateForEdits(shifts); - viewport.setStartRes(seq.findIndex(startRes) - 1); - viewport.firePropertyChange("alignment", null, viewport.getAlignment() - .getSequences()); + ranges.setStartRes(seq.findIndex(startRes) - 1); + viewport.firePropertyChange("alignment", null, al.getSequences()); } public void removeAllGapsMenuItem_actionPerformed() { - int start = 0, end = viewport.getAlignment().getWidth() - 1; + AlignmentI al = viewport.getAlignment(); + ViewportRanges ranges = viewport.getRanges(); + int start = 0; + int end = ranges.getAbsoluteAlignmentWidth() - 1; SequenceI[] seqs; if (viewport.getSelectionGroup() != null) @@ -2419,16 +2428,15 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, // This is to maintain viewport position on first residue // of first sequence - SequenceI seq = viewport.getAlignment().getSequenceAt(0); - int startRes = seq.findPosition(viewport.startRes); + SequenceI seq = al.getSequenceAt(0); + int startRes = seq.findPosition(ranges.getStartRes()); addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end, - viewport.getAlignment())); + al)); - viewport.setStartRes(seq.findIndex(startRes) - 1); + ranges.setStartRes(seq.findIndex(startRes) - 1); - viewport.firePropertyChange("alignment", null, viewport.getAlignment() - .getSequences()); + viewport.firePropertyChange("alignment", null, al.getSequences()); } diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java index fc087c6..065c503 100644 --- a/src/jalview/appletgui/AlignViewport.java +++ b/src/jalview/appletgui/AlignViewport.java @@ -35,16 +35,16 @@ import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShader; import jalview.schemes.ColourSchemeProperty; import jalview.schemes.UserColourScheme; -import jalview.structure.CommandListener; import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import java.awt.Font; public class AlignViewport extends AlignmentViewport implements - SelectionSource, VamsasSource, CommandListener + SelectionSource { boolean cursorMode = false; @@ -75,12 +75,10 @@ public class AlignViewport extends AlignmentViewport implements calculator = new jalview.workers.AlignCalcManager(); this.applet = applet; alignment = al; + ranges = new ViewportRanges(this.alignment); // we always pad gaps this.setPadGaps(true); - this.startRes = 0; - this.endRes = al.getWidth() - 1; - this.startSeq = 0; - this.endSeq = al.getHeight() - 1; + if (applet != null) { // get the width and height scaling factors if they were specified @@ -299,7 +297,7 @@ public class AlignViewport extends AlignmentViewport implements public void resetSeqLimits(int height) { - setEndSeq(height / getCharHeight()); + ranges.setEndSeq(height / getCharHeight()); } public void setCurrentTree(NJTree tree) diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index e97c347..3ae0394 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -28,6 +28,7 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceI; import jalview.structure.StructureSelectionManager; +import jalview.viewmodel.ViewportRanges; import java.awt.BorderLayout; import java.awt.Color; @@ -65,6 +66,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, AnnotationLabels alabels; + ViewportRanges vpRanges; + // this value is set false when selection area being dragged boolean fastPaint = true; @@ -73,6 +76,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, { alignFrame = null; av = null; + vpRanges = null; seqPanel = null; seqPanelHolder = null; sequenceHolderPanel = null; @@ -96,6 +100,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, alignFrame = af; this.av = av; + vpRanges = av.getRanges(); seqPanel = new SeqPanel(av, this); idPanel = new IdPanel(av, this); scalePanel = new ScalePanel(av, this); @@ -126,7 +131,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, @Override public void componentResized(ComponentEvent evt) { - setScrollValues(av.getStartRes(), av.getStartSeq()); + setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq()); if (getSize().height > 0 && annotationPanelHolder.getSize().height > 0) { @@ -383,7 +388,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, */ if (centre) { - int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1; + int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1; start = Math.max(start - offset, 0); end = Math.min(end + offset, seq.getEnd() - 1); } @@ -468,33 +473,34 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, // setScrollValues(start, seqIndex); // } // logic copied from jalview.gui.AlignmentPanel: - if ((startv = av.getStartRes()) >= start) + if ((startv = vpRanges.getStartRes()) >= start) { /* * Scroll left to make start of search results visible */ setScrollValues(start - 1, seqIndex); } - else if ((endv = av.getEndRes()) <= end) + else if ((endv = vpRanges.getEndRes()) <= end) { /* * Scroll right to make end of search results visible */ setScrollValues(startv + 1 + end - endv, seqIndex); } - else if ((starts = av.getStartSeq()) > seqIndex) + else if ((starts = vpRanges.getStartSeq()) > seqIndex) { /* * Scroll up to make start of search results visible */ - setScrollValues(av.getStartRes(), seqIndex); + setScrollValues(vpRanges.getStartRes(), seqIndex); } - else if ((ends = av.getEndSeq()) <= seqIndex) + else if ((ends = vpRanges.getEndSeq()) <= seqIndex) { /* * Scroll down to make end of search results visible */ - setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); + setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends + + 1); } /* * Else results are already visible - no need to scroll @@ -516,10 +522,11 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, { int cwidth = seqPanel.seqCanvas .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width); - if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth)) + if (res <= vpRanges.getStartRes() + || res >= (vpRanges.getStartRes() + cwidth)) { vscroll.setValue(res / cwidth); - av.startRes = vscroll.getValue() * cwidth; + vpRanges.setStartRes(vscroll.getValue() * cwidth); } } @@ -632,8 +639,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, public void setWrapAlignment(boolean wrap) { - av.startSeq = 0; - av.startRes = 0; + vpRanges.setStartSeq(0); + vpRanges.setStartRes(0); scalePanelHolder.setVisible(!wrap); hscroll.setVisible(!wrap); @@ -724,7 +731,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, { x = 0; } - ; + hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth(); vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight(); @@ -762,17 +769,10 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, x = 0; } - av.setStartSeq(y); - - int endSeq = y + vextent; - if (endSeq > av.getAlignment().getHeight()) - { - endSeq = av.getAlignment().getHeight(); - } - - av.setEndSeq(endSeq); - av.setStartRes(x); - av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av + vpRanges.setStartSeq(y); + vpRanges.setEndSeq(y + vextent); + vpRanges.setStartRes(x); + vpRanges.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av .getCharWidth())) - 1); hscroll.setValues(x, hextent, 0, width); @@ -789,8 +789,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, @Override public void adjustmentValueChanged(AdjustmentEvent evt) { - int oldX = av.getStartRes(); - int oldY = av.getStartSeq(); + int oldX = vpRanges.getStartRes(); + int oldY = vpRanges.getStartSeq(); if (evt == null || evt.getSource() == apvscroll) { @@ -804,8 +804,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, if (evt == null || evt.getSource() == hscroll) { int x = hscroll.getValue(); - av.setStartRes(x); - av.setEndRes(x + seqPanel.seqCanvas.getSize().width + vpRanges.setStartRes(x); + vpRanges.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() - 1); } @@ -816,14 +816,14 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, { int rowSize = seqPanel.seqCanvas .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width); - av.setStartRes(vscroll.getValue() * rowSize); - av.setEndRes((vscroll.getValue() + 1) * rowSize); + vpRanges.setStartRes(vscroll.getValue() * rowSize); + vpRanges.setEndRes((vscroll.getValue() + 1) * rowSize); } else { - av.setStartSeq(offy); - av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height - / av.getCharHeight()); + vpRanges.setStartSeq(offy); + vpRanges.setEndSeq(offy + seqPanel.seqCanvas.getSize().height + / av.getCharHeight() - 1); } } @@ -832,8 +832,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, overviewPanel.setBoxPosition(); } - int scrollX = av.startRes - oldX; - int scrollY = av.startSeq - oldY; + int scrollX = vpRanges.getStartRes() - oldX; + int scrollY = vpRanges.getStartSeq() - oldY; if (av.getWrapAlignment() || !fastPaint || av.MAC) { @@ -843,13 +843,13 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, { // Make sure we're not trying to draw a panel // larger than the visible window - if (scrollX > av.endRes - av.startRes) + if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes()) { - scrollX = av.endRes - av.startRes; + scrollX = vpRanges.getEndRes() - vpRanges.getStartRes(); } - else if (scrollX < av.startRes - av.endRes) + else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes()) { - scrollX = av.startRes - av.endRes; + scrollX = vpRanges.getStartRes() - vpRanges.getEndRes(); } idPanel.idCanvas.fastPaint(scrollY); @@ -858,7 +858,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, scalePanel.repaint(); if (av.isShowAnnotation()) { - annotationPanel.fastPaint(av.getStartRes() - oldX); + annotationPanel.fastPaint(vpRanges.getStartRes() - oldX); } } sendViewPosition(); @@ -955,8 +955,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, private void sendViewPosition() { StructureSelectionManager.getStructureSelectionManager(av.applet) - .sendViewPosition(this, av.startRes, av.endRes, av.startSeq, - av.endSeq); + .sendViewPosition(this, vpRanges.getStartRes(), + vpRanges.getEndRes(), vpRanges.getStartSeq(), + vpRanges.getEndSeq()); } /** @@ -1024,7 +1025,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, } else { - setScrollValues(av.getStartRes(), av.getStartSeq()); + setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq()); } seqPanel.seqCanvas.repaint(); diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index b28ccc7..ad74b25 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -339,7 +339,8 @@ public class AnnotationLabels extends Panel implements ActionListener, av.calcPanelHeight()); f.height += dif; ap.seqPanelHolder.setPreferredSize(f); - ap.setScrollValues(av.getStartRes(), av.getStartSeq()); + ap.setScrollValues(av.getRanges().getStartRes(), av.getRanges() + .getStartSeq()); ap.validate(); // ap.paintAlignment(true); ap.addNotify(); diff --git a/src/jalview/appletgui/AnnotationPanel.java b/src/jalview/appletgui/AnnotationPanel.java index 6012c1a..0ec7adf 100755 --- a/src/jalview/appletgui/AnnotationPanel.java +++ b/src/jalview/appletgui/AnnotationPanel.java @@ -462,7 +462,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, } } - int column = evt.getX() / av.getCharWidth() + av.getStartRes(); + int column = evt.getX() / av.getCharWidth() + + av.getRanges().getStartRes(); if (av.hasHiddenColumns()) { @@ -618,7 +619,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, gg.setColor(Color.white); gg.fillRect(0, 0, getSize().width, getSize().height); - drawComponent(gg, av.startRes, av.endRes + 1); + drawComponent(gg, av.getRanges().getStartRes(), av.getRanges() + .getEndRes() + 1); g.drawImage(image, 0, 0, this); } @@ -635,7 +637,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI, gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal * av.getCharWidth(), 0); - int sr = av.startRes, er = av.endRes + 1, transX = 0; + int sr = av.getRanges().getStartRes(), er = av.getRanges().getEndRes() + 1, transX = 0; if (horizontal > 0) // scrollbar pulled right, image to the left { diff --git a/src/jalview/appletgui/IdCanvas.java b/src/jalview/appletgui/IdCanvas.java index d72e91f..abcbd70 100755 --- a/src/jalview/appletgui/IdCanvas.java +++ b/src/jalview/appletgui/IdCanvas.java @@ -21,6 +21,7 @@ package jalview.appletgui; import jalview.datamodel.SequenceI; +import jalview.viewmodel.ViewportRanges; import java.awt.Color; import java.awt.Font; @@ -103,28 +104,32 @@ public class IdCanvas extends Panel return; } + ViewportRanges ranges = av.getRanges(); + gg.copyArea(0, 0, getSize().width, imgHeight, 0, -vertical * av.getCharHeight()); - int ss = av.startSeq, es = av.endSeq, transY = 0; + int ss = ranges.getStartSeq(), es = ranges.getEndSeq(), transY = 0; if (vertical > 0) // scroll down { ss = es - vertical; - if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time + if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page + // at a + // time { - ss = av.startSeq; + ss = ranges.getStartSeq(); } else { - transY = imgHeight - vertical * av.getCharHeight(); + transY = imgHeight - ((vertical + 1) * av.getCharHeight()); } } else if (vertical < 0) { es = ss - vertical; - if (es > av.endSeq) + if (es > ranges.getEndSeq()) { - es = av.endSeq; + es = ranges.getEndSeq(); } } @@ -180,7 +185,7 @@ public class IdCanvas extends Panel gg.setFont(italic); gg.fillRect(0, 0, getSize().width, getSize().height); - drawIds(av.startSeq, av.endSeq); + drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq()); g.drawImage(image, 0, 0, this); } @@ -233,9 +238,10 @@ public class IdCanvas extends Panel int cHeight = alheight * avcharHeight + hgap + annotationHeight; - int rowSize = av.getEndRes() - av.getStartRes(); + int rowSize = av.getRanges().getEndRes() + - av.getRanges().getStartRes(); // Draw the rest of the panels - for (int ypos = hgap, row = av.startRes; (ypos <= getSize().height) + for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getSize().height) && (row < maxwidth); ypos += cHeight, row += rowSize) { for (int i = starty; i < alheight; i++) @@ -263,7 +269,7 @@ public class IdCanvas extends Panel { // Now draw the id strings SequenceI seq; - for (int i = starty; i < endy; i++) + for (int i = starty; i <= endy; i++) { seq = av.getAlignment().getSequenceAt(i); diff --git a/src/jalview/appletgui/IdPanel.java b/src/jalview/appletgui/IdPanel.java index b03a638..e47c50a 100755 --- a/src/jalview/appletgui/IdPanel.java +++ b/src/jalview/appletgui/IdPanel.java @@ -253,13 +253,13 @@ public class IdPanel extends Panel implements MouseListener, return; } - if (mouseDragging && e.getY() < 0 && av.getStartSeq() > 0) + if (mouseDragging && e.getY() < 0 && av.getRanges().getStartSeq() > 0) { scrollThread = new ScrollThread(true); } if (mouseDragging && e.getY() >= getSize().height - && av.getAlignment().getHeight() > av.getEndSeq()) + && av.getAlignment().getHeight() > av.getRanges().getEndSeq()) { scrollThread = new ScrollThread(false); } @@ -398,9 +398,10 @@ public class IdPanel extends Panel implements MouseListener, int index = av.getAlignment().findIndex(list.get(0)); // do we need to scroll the panel? - if (av.getStartSeq() > index || av.getEndSeq() < index) + if (av.getRanges().getStartSeq() > index + || av.getRanges().getEndSeq() < index) { - alignPanel.setScrollValues(av.getStartRes(), index); + alignPanel.setScrollValues(av.getRanges().getStartRes(), index); } } @@ -431,10 +432,10 @@ public class IdPanel extends Panel implements MouseListener, if (alignPanel.scrollUp(up)) { // scroll was ok, so add new sequence to selection - int seq = av.getStartSeq(); + int seq = av.getRanges().getStartSeq(); if (!up) { - seq = av.getEndSeq(); + seq = av.getRanges().getEndSeq(); } if (seq < lastid) diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 251e1c8..2fc5716 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -20,8 +20,9 @@ */ package jalview.appletgui; -import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.viewmodel.OverviewDimensions; import java.awt.Color; import java.awt.Dimension; @@ -38,38 +39,34 @@ import java.awt.event.MouseMotionListener; public class OverviewPanel extends Panel implements Runnable, MouseMotionListener, MouseListener { - Image miniMe; + private OverviewDimensions od; - Image offscreen; + private Image miniMe; - AlignViewport av; + private Image offscreen; - AlignmentPanel ap; + private AlignViewport av; - float scalew = 1f; + private AlignmentPanel ap; - float scaleh = 1f; + private boolean resizing = false; - public int width, sequencesHeight; - - int graphHeight = 20; - - int boxX = -1, boxY = -1, boxWidth = -1, boxHeight = -1; - - boolean resizing = false; + // This is set true if the user resizes whilst + // the overview is being calculated + private boolean resizeAgain = false; // Can set different properties in this seqCanvas than // main visible SeqCanvas - SequenceRenderer sr; + private SequenceRenderer sr; - FeatureRenderer fr; + private FeatureRenderer fr; - Frame nullFrame; + private Frame nullFrame; - public OverviewPanel(AlignmentPanel ap) + public OverviewPanel(AlignmentPanel alPanel) { - this.av = ap.av; - this.ap = ap; + this.av = alPanel.av; + this.ap = alPanel; setLayout(null); nullFrame = new Frame(); nullFrame.addNotify(); @@ -80,45 +77,17 @@ public class OverviewPanel extends Panel implements Runnable, sr.forOverview = true; fr = new FeatureRenderer(av); - // scale the initial size of overviewpanel to shape of alignment - float initialScale = (float) av.getAlignment().getWidth() - / (float) av.getAlignment().getHeight(); - - if (av.getSequenceConsensusHash() == null) - { - graphHeight = 0; - } + od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation()); - if (av.getAlignment().getWidth() > av.getAlignment().getHeight()) - { - // wider - width = 400; - sequencesHeight = (int) (400f / initialScale); - if (sequencesHeight < 40) - { - sequencesHeight = 40; - } - } - else - { - // taller - width = (int) (400f * initialScale); - sequencesHeight = 300; - if (width < 120) - { - width = 120; - } - } - - setSize(new Dimension(width, sequencesHeight + graphHeight)); + setSize(new Dimension(od.getWidth(), od.getHeight())); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent evt) { - if (getSize().width != width - || getSize().height != sequencesHeight + graphHeight) + if ((getWidth() != od.getWidth()) + || (getHeight() != (od.getHeight()))) { updateOverviewImage(); } @@ -156,79 +125,32 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mousePressed(MouseEvent evt) { - boxX = evt.getX(); - boxY = evt.getY(); - checkValid(); + mouseAction(evt); } @Override public void mouseReleased(MouseEvent evt) { - boxX = evt.getX(); - boxY = evt.getY(); - checkValid(); + mouseAction(evt); } @Override public void mouseDragged(MouseEvent evt) { - boxX = evt.getX(); - boxY = evt.getY(); - checkValid(); + mouseAction(evt); } - void checkValid() + private void mouseAction(MouseEvent evt) { - if (boxY < 0) - { - boxY = 0; - } - - if (boxY > (sequencesHeight - boxHeight)) - { - boxY = sequencesHeight - boxHeight + 1; - } - - if (boxX < 0) - { - boxX = 0; - } - - if (boxX > (width - boxWidth)) - { - if (av.hasHiddenColumns()) - { - // Try smallest possible box - boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew); - } - boxX = width - boxWidth; - } - - int col = (int) (boxX / scalew / av.getCharWidth()); - int row = (int) (boxY / scaleh / av.getCharHeight()); - - if (av.hasHiddenColumns()) - { - if (!av.getColumnSelection().isVisible(col)) - { - return; - } - - col = av.getColumnSelection().findColumnPosition(col); - } - - if (av.hasHiddenRows()) - { - row = av.getAlignment().getHiddenSequences() - .findIndexWithoutHiddenSeqs(row); - } - - ap.setScrollValues(col, row); + od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment() + .getHiddenSequences(), av.getColumnSelection(), av + .getRanges()); + ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); ap.paintAlignment(false); } /** - * DOCUMENT ME! + * Updates the overview image when the related alignment panel is updated */ public void updateOverviewImage() { @@ -247,27 +169,20 @@ public class OverviewPanel extends Panel implements Runnable, if ((getSize().width > 0) && (getSize().height > 0)) { - width = getSize().width; - sequencesHeight = getSize().height - graphHeight; + od.setWidth(getSize().width); + od.setHeight(getSize().height); } - setSize(new Dimension(width, sequencesHeight + graphHeight)); + setSize(new Dimension(od.getWidth(), od.getHeight())); Thread thread = new Thread(this); thread.start(); repaint(); } - // This is set true if the user resizes whilst - // the overview is being calculated - boolean resizeAgain = false; - @Override public void run() { miniMe = null; - int alwidth = av.getAlignment().getWidth(); - int alheight = av.getAlignment().getHeight() - + av.getAlignment().getHiddenSequences().getSize(); if (av.isShowSequenceFeatures()) { @@ -276,132 +191,35 @@ public class OverviewPanel extends Panel implements Runnable, if (getSize().width > 0 && getSize().height > 0) { - width = getSize().width; - sequencesHeight = getSize().height - graphHeight; + od.setWidth(getSize().width); + od.setHeight(getSize().height); } - setSize(new Dimension(width, sequencesHeight + graphHeight)); - - int fullsizeWidth = alwidth * av.getCharWidth(); - int fullsizeHeight = alheight * av.getCharHeight(); - - scalew = (float) width / (float) fullsizeWidth; - scaleh = (float) sequencesHeight / (float) fullsizeHeight; + setSize(new Dimension(od.getWidth(), od.getHeight())); - miniMe = nullFrame.createImage(width, sequencesHeight + graphHeight); - offscreen = nullFrame.createImage(width, sequencesHeight + graphHeight); + miniMe = nullFrame.createImage(od.getWidth(), od.getHeight()); + offscreen = nullFrame.createImage(od.getWidth(), od.getHeight()); Graphics mg = miniMe.getGraphics(); - float sampleCol = (float) alwidth / (float) width; - float sampleRow = (float) alheight / (float) sequencesHeight; - - int lastcol = 0, lastrow = 0; - int xstart = 0, ystart = 0; - Color color = Color.yellow; - int row, col, sameRow = 0, sameCol = 0; - jalview.datamodel.SequenceI seq; - final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av - .hasHiddenColumns(); - boolean hiddenRow = false; - AlignmentI alignment = av.getAlignment(); - - FeatureColourFinder finder = new FeatureColourFinder(fr); - for (row = 0; row <= sequencesHeight; row++) - { - if (resizeAgain) - { - break; - } - if ((int) (row * sampleRow) == lastrow) - { - sameRow++; - continue; - } - - hiddenRow = false; - if (hasHiddenRows) - { - seq = alignment.getHiddenSequences().getHiddenSequence(lastrow); - if (seq == null) - { - int index = alignment.getHiddenSequences() - .findIndexWithoutHiddenSeqs(lastrow); - seq = alignment.getSequenceAt(index); - } - else - { - hiddenRow = true; - } - } - else - { - seq = alignment.getSequenceAt(lastrow); - } - - for (col = 0; col < width; col++) - { - if ((int) (col * sampleCol) == lastcol - && (int) (row * sampleRow) == lastrow) - { - sameCol++; - continue; - } - - lastcol = (int) (col * sampleCol); - - if (seq.getLength() > lastcol) - { - color = sr.getResidueColour(seq, lastcol, finder); - } - else - { - color = Color.white; - } - - if (hiddenRow - || (hasHiddenCols && !av.getColumnSelection().isVisible( - lastcol))) - { - color = color.darker().darker(); - } - - mg.setColor(color); - if (sameCol == 1 && sameRow == 1) - { - mg.drawLine(xstart, ystart, xstart, ystart); - } - else - { - mg.fillRect(xstart, ystart, sameCol, sameRow); - } + int alwidth = av.getAlignment().getWidth(); + int alheight = av.getAlignment().getAbsoluteHeight(); + float sampleCol = alwidth / (float) od.getWidth(); + float sampleRow = alheight / (float) od.getSequencesHeight(); - xstart = col; - sameCol = 1; - } - lastrow = (int) (row * sampleRow); - ystart = row; - sameRow = 1; - } + buildImage(sampleRow, sampleCol, mg); - if (av.getAlignmentConservationAnnotation() != null) + if (av.isShowAnnotation()) { - for (col = 0; col < width; col++) + for (int col = 0; col < od.getWidth() && !resizeAgain; col++) { - if (resizeAgain) - { - break; - } - lastcol = (int) (col * sampleCol); - { - mg.translate(col, sequencesHeight); - ap.annotationPanel.renderer.drawGraph(mg, - av.getAlignmentConservationAnnotation(), - av.getAlignmentConservationAnnotation().annotations, - (int) (sampleCol) + 1, graphHeight, - (int) (col * sampleCol), (int) (col * sampleCol) + 1); - mg.translate(-col, -sequencesHeight); - } + mg.translate(col, od.getSequencesHeight()); + ap.annotationPanel.renderer.drawGraph(mg, + av.getAlignmentConservationAnnotation(), + av.getAlignmentConservationAnnotation().annotations, + (int) (sampleCol) + 1, od.getGraphHeight(), + (int) (col * sampleCol), (int) (col * sampleCol) + 1); + mg.translate(-col, -od.getSequencesHeight()); } } System.gc(); @@ -417,52 +235,104 @@ public class OverviewPanel extends Panel implements Runnable, } } - public void setBoxPosition() + /* + * Build the overview panel image + */ + private void buildImage(float sampleRow, float sampleCol, Graphics mg) { - int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth(); - int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment() - .getHiddenSequences().getSize()) - * av.getCharHeight(); - - int startRes = av.getStartRes(); - int endRes = av.getEndRes(); + int lastcol = 0; + int lastrow = 0; + int xstart = 0; + int ystart = 0; + Color color = Color.yellow; + int sameRow = 0; + int sameCol = 0; - if (av.hasHiddenColumns()) - { - startRes = av.getColumnSelection().adjustForHiddenColumns(startRes); - endRes = av.getColumnSelection().adjustForHiddenColumns(endRes); - } + SequenceI seq = null; + FeatureColourFinder finder = new FeatureColourFinder(fr); - int startSeq = av.startSeq; - int endSeq = av.endSeq; + final boolean hasHiddenCols = av.hasHiddenColumns(); + boolean hiddenRow = false; - if (av.hasHiddenRows()) + for (int row = 0; row <= od.getSequencesHeight() && !resizeAgain; row++) { - startSeq = av.getAlignment().getHiddenSequences() - .adjustForHiddenSeqs(startSeq); - - endSeq = av.getAlignment().getHiddenSequences() - .adjustForHiddenSeqs(endSeq); + if ((int) (row * sampleRow) == lastrow) + { + sameRow++; + } + else + { + // get the sequence which would be at alignment index 'lastrow' if no + // columns were hidden, and determine whether it is hidden or not + hiddenRow = av.getAlignment().isHidden(lastrow); + seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow); + for (int col = 0; col < od.getWidth(); col++) + { + if ((int) (col * sampleCol) == lastcol + && (int) (row * sampleRow) == lastrow) + { + sameCol++; + } + else + { + lastcol = (int) (col * sampleCol); + + color = getColumnColourFromSequence(seq, hiddenRow, + hasHiddenCols, lastcol, finder); + + mg.setColor(color); + if (sameCol == 1 && sameRow == 1) + { + mg.drawLine(xstart, ystart, xstart, ystart); + } + else + { + mg.fillRect(xstart, ystart, sameCol, sameRow); + } + + xstart = col; + sameCol = 1; + } + } + lastrow = (int) (row * sampleRow); + ystart = row; + sameRow = 1; + } } + } - scalew = (float) width / (float) fullsizeWidth; - scaleh = (float) sequencesHeight / (float) fullsizeHeight; - - boxX = (int) (startRes * av.getCharWidth() * scalew); - boxY = (int) (startSeq * av.getCharHeight() * scaleh); - - if (av.hasHiddenColumns()) + /* + * Find the colour of a sequence at a specified column position + */ + private Color getColumnColourFromSequence( + jalview.datamodel.SequenceI seq, boolean hiddenRow, + boolean hasHiddenCols, int lastcol, FeatureColourFinder finder) + { + Color color = Color.white; + if (seq.getLength() > lastcol) { - boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew); + color = sr.getResidueColour(seq, lastcol, finder); } - else + + if (hiddenRow + || (hasHiddenCols && !av.getColumnSelection() + .isVisible(lastcol))) { - boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew); + color = color.darker().darker(); } + return color; + } - boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh); - + /** + * Update the overview panel box when the associated alignment panel is + * changed + * + */ + public void setBoxPosition() + { + od.setBoxPosition(av.getAlignment() + .getHiddenSequences(), av.getColumnSelection(), av.getRanges()); repaint(); } @@ -480,8 +350,7 @@ public class OverviewPanel extends Panel implements Runnable, { og.drawImage(miniMe, 0, 0, this); og.setColor(Color.red); - og.drawRect(boxX, boxY, boxWidth, boxHeight); - og.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2); + od.drawBox(og); g.drawImage(offscreen, 0, 0, this); } } diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index ed07b63..15d82a5 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -76,7 +76,7 @@ public class ScalePanel extends Panel implements MouseMotionListener, @Override public void mousePressed(MouseEvent evt) { - int x = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); final int res; if (av.hasHiddenColumns()) @@ -229,7 +229,8 @@ public class ScalePanel extends Panel implements MouseMotionListener, { mouseDragging = false; - int res = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int res = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); if (res > av.getAlignment().getWidth()) { @@ -276,7 +277,8 @@ public class ScalePanel extends Panel implements MouseMotionListener, mouseDragging = true; ColumnSelection cs = av.getColumnSelection(); - int res = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int res = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); res = Math.max(0, res); res = cs.adjustForHiddenColumns(res); res = Math.min(res, av.getAlignment().getWidth() - 1); @@ -324,7 +326,8 @@ public class ScalePanel extends Panel implements MouseMotionListener, return; } - int res = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int res = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); res = av.getColumnSelection().adjustForHiddenColumns(res); @@ -350,7 +353,8 @@ public class ScalePanel extends Panel implements MouseMotionListener, @Override public void paint(Graphics g) { - drawScale(g, av.getStartRes(), av.getEndRes(), getSize().width, + drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(), + getSize().width, getSize().height); } diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index 5ab3459..ed8a46d 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -27,6 +27,7 @@ import jalview.datamodel.SequenceI; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import java.awt.Color; import java.awt.FontMetrics; @@ -211,17 +212,19 @@ public class SeqCanvas extends Panel return; } + ViewportRanges ranges = av.getRanges(); + updateViewport(); // Its possible on certain browsers that the call to fastpaint // is faster than it can paint, so this check here catches // this possibility - if (lastsr + horizontal != av.startRes) + if (lastsr + horizontal != ranges.getStartRes()) { - horizontal = av.startRes - lastsr; + horizontal = ranges.getStartRes() - lastsr; } - lastsr = av.startRes; + lastsr = ranges.getStartRes(); fastPaint = true; gg.copyArea(horizontal * avcharWidth, vertical * avcharHeight, imgWidth @@ -229,7 +232,9 @@ public class SeqCanvas extends Panel imgHeight - vertical * avcharHeight, -horizontal * avcharWidth, -vertical * avcharHeight); - int sr = av.startRes, er = av.endRes, ss = av.startSeq, es = av.endSeq, transX = 0, transY = 0; + int sr = ranges.getStartRes(), er = ranges.getEndRes(), ss = ranges + .getStartSeq(), es = ranges + .getEndSeq(), transX = 0, transY = 0; if (horizontal > 0) // scrollbar pulled right, image to the left { @@ -244,21 +249,23 @@ public class SeqCanvas extends Panel else if (vertical > 0) // scroll down { ss = es - vertical; - if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time + if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page + // at a + // time { - ss = av.startSeq; + ss = ranges.getStartSeq(); } else { - transY = imgHeight - vertical * avcharHeight; + transY = imgHeight - ((vertical + 1) * avcharHeight); } } else if (vertical < 0) { es = ss - vertical; - if (es > av.endSeq) + if (es > ranges.getEndSeq()) { - es = av.endSeq; + es = ranges.getEndSeq(); } } @@ -329,13 +336,16 @@ public class SeqCanvas extends Panel gg.setColor(Color.white); gg.fillRect(0, 0, imgWidth, imgHeight); + ViewportRanges ranges = av.getRanges(); + if (av.getWrapAlignment()) { - drawWrappedPanel(gg, imgWidth, imgHeight, av.startRes); + drawWrappedPanel(gg, imgWidth, imgHeight, ranges.getStartRes()); } else { - drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0); + drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), + ranges.getStartSeq(), ranges.getEndSeq(), 0); } g.drawImage(img, 0, 0, this); @@ -421,7 +431,7 @@ public class SeqCanvas extends Panel av.setWrappedWidth(cWidth); - av.endRes = av.startRes + cWidth; + av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth); int endx; int ypos = hgap; @@ -610,7 +620,7 @@ public class SeqCanvas extends Panel // / First draw the sequences // /////////////////////////// - for (int i = startSeq; i < endSeq; i++) + for (int i = startSeq; i <= endSeq; i++) { nextSeq = av.getAlignment().getSequenceAt(i); @@ -694,7 +704,7 @@ public class SeqCanvas extends Panel int bottom = -1; int alHeight = av.getAlignment().getHeight() - 1; - for (i = startSeq; i < endSeq; i++) + for (i = startSeq; i <= endSeq; i++) { sx = (group.getStartRes() - startRes) * avcharWidth; sy = offset + ((i - startSeq) * avcharHeight); diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index 1352fe9..0e12703 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -41,6 +41,7 @@ import jalview.structure.VamsasSource; import jalview.util.MappingUtils; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import java.awt.BorderLayout; import java.awt.Font; @@ -226,16 +227,17 @@ public class SeqPanel extends Panel implements MouseMotionListener, } else { - while (seqCanvas.cursorY < av.startSeq) + ViewportRanges ranges = av.getRanges(); + while (seqCanvas.cursorY < ranges.getStartSeq()) { ap.scrollUp(true); } - while (seqCanvas.cursorY + 1 > av.endSeq) + while (seqCanvas.cursorY + 1 > ranges.getEndSeq()) { ap.scrollUp(false); } while (seqCanvas.cursorX < av.getColumnSelection() - .adjustForHiddenColumns(av.startRes)) + .adjustForHiddenColumns(ranges.getStartRes())) { if (!ap.scrollRight(false)) @@ -244,7 +246,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, } } while (seqCanvas.cursorX > av.getColumnSelection() - .adjustForHiddenColumns(av.endRes)) + .adjustForHiddenColumns(ranges.getEndRes())) { if (!ap.scrollRight(true)) { @@ -624,14 +626,14 @@ public class SeqPanel extends Panel implements MouseMotionListener, } wrappedBlock = y / cHeight; - wrappedBlock += av.getStartRes() / cwidth; + wrappedBlock += av.getRanges().getStartRes() / cwidth; res = wrappedBlock * cwidth + x / av.getCharWidth(); } else { - res = (x / av.getCharWidth()) + av.getStartRes(); + res = (x / av.getCharWidth()) + av.getRanges().getStartRes(); } if (av.hasHiddenColumns()) @@ -681,7 +683,9 @@ public class SeqPanel extends Panel implements MouseMotionListener, } else { - seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av + seq = Math.min((y / av.getCharHeight()) + + av.getRanges().getStartSeq(), + av .getAlignment().getHeight() - 1); if (seq < 0) { @@ -1643,8 +1647,10 @@ public class SeqPanel extends Panel implements MouseMotionListener, oldSeq = -1; } - if (res > av.endRes || res < av.startRes || y < av.startSeq - || y > av.endSeq) + if (res > av.getRanges().getEndRes() + || res < av.getRanges().getStartRes() + || y < av.getRanges().getStartSeq() + || y > av.getRanges().getEndSeq()) { mouseExited(evt); } @@ -1742,13 +1748,15 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (evt != null) { - if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0) + if (mouseDragging && evt.getY() < 0 + && av.getRanges().getStartSeq() > 0) { running = ap.scrollUp(true); } if (mouseDragging && evt.getY() >= getSize().height - && av.getAlignment().getHeight() > av.getEndSeq()) + && av.getAlignment().getHeight() > av.getRanges() + .getEndSeq()) { running = ap.scrollUp(false); } @@ -1890,8 +1898,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, public void scrollTo(int row, int column) { - row = row < 0 ? ap.av.startSeq : row; - column = column < 0 ? ap.av.startRes : column; + row = row < 0 ? ap.av.getRanges().getStartSeq() : row; + column = column < 0 ? ap.av.getRanges().getStartRes() : column; ap.scrollTo(column, column, row, true, true); } @@ -1903,8 +1911,9 @@ public class SeqPanel extends Panel implements MouseMotionListener, public void scrollToRow(int row) { - row = row < 0 ? ap.av.startSeq : row; - ap.scrollTo(ap.av.startRes, ap.av.startRes, row, true, true); + row = row < 0 ? ap.av.getRanges().getStartSeq() : row; + ap.scrollTo(ap.av.getRanges().getStartRes(), ap.av.getRanges() + .getStartRes(), row, true, true); } /** @@ -1915,8 +1924,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, public void scrollToColumn(int column) { - column = column < 0 ? ap.av.startRes : column; - ap.scrollTo(column, column, ap.av.startSeq, true, true); + column = column < 0 ? ap.av.getRanges().getStartRes() : column; + ap.scrollTo(column, column, ap.av.getRanges().getStartSeq(), true, true); } /** diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index a6f2bf4..41488ea 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -185,14 +185,7 @@ public class Alignment implements AlignmentI return AlignmentUtils.getSequencesByName(this); } - /** - * DOCUMENT ME! - * - * @param i - * DOCUMENT ME! - * - * @return DOCUMENT ME! - */ + @Override public SequenceI getSequenceAt(int i) { @@ -206,6 +199,28 @@ public class Alignment implements AlignmentI return null; } + @Override + public SequenceI getSequenceAtAbsoluteIndex(int i) + { + SequenceI seq = null; + if (getHiddenSequences().getSize() > 0) + { + seq = getHiddenSequences().getHiddenSequence(i); + if (seq == null) + { + // didn't find the sequence in the hidden sequences, get it from the + // alignment + int index = getHiddenSequences().findIndexWithoutHiddenSeqs(i); + seq = getSequenceAt(index); + } + } + else + { + seq = getSequenceAt(i); + } + return seq; + } + /** * Adds a sequence to the alignment. Recalculates maxLength and size. Note * this currently does not recalculate whether or not the alignment is @@ -320,30 +335,21 @@ public class Alignment implements AlignmentI } } - /** - * DOCUMENT ME! - * - * @param s - * DOCUMENT ME! - */ @Override public void deleteSequence(SequenceI s) { - deleteSequence(findIndex(s)); + synchronized (sequences) + { + deleteSequence(findIndex(s)); + } } - /** - * DOCUMENT ME! - * - * @param i - * DOCUMENT ME! - */ @Override public void deleteSequence(int i) { - if (i > -1 && i < getHeight()) + synchronized (sequences) { - synchronized (sequences) + if (i > -1 && i < getHeight()) { sequences.remove(i); hiddenSequences.adjustHeightSequenceDeleted(i); @@ -351,6 +357,18 @@ public class Alignment implements AlignmentI } } + @Override + public void deleteHiddenSequence(int i) + { + synchronized (sequences) + { + if (i > -1 && i < getHeight()) + { + sequences.remove(i); + } + } + } + /* * (non-Javadoc) * @@ -668,22 +686,19 @@ public class Alignment implements AlignmentI return -1; } - /** - * DOCUMENT ME! - * - * @return DOCUMENT ME! - */ + @Override public int getHeight() { return sequences.size(); } - /** - * DOCUMENT ME! - * - * @return DOCUMENT ME! - */ + @Override + public int getAbsoluteHeight() + { + return sequences.size() + getHiddenSequences().getSize(); + } + @Override public int getWidth() { @@ -769,6 +784,12 @@ public class Alignment implements AlignmentI return true; } + @Override + public boolean isHidden(int alignmentIndex) + { + return (getHiddenSequences().getHiddenSequence(alignmentIndex) != null); + } + /** * Delete all annotations, including auto-calculated if the flag is set true. * Returns true if at least one annotation was deleted, else false. diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index 5d185cd..2abb1f8 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -31,13 +31,22 @@ import java.util.Set; public interface AlignmentI extends AnnotatedCollectionI { /** - * Calculates the number of sequences in an alignment + * Calculates the number of sequences in an alignment, excluding hidden + * sequences * * @return Number of sequences in alignment */ int getHeight(); /** + * Calculates the number of sequences in an alignment, including hidden + * sequences + * + * @return Number of sequences in alignment + */ + int getAbsoluteHeight(); + + /** * * Calculates the maximum width of the alignment, including gaps. * @@ -65,6 +74,15 @@ public interface AlignmentI extends AnnotatedCollectionI boolean isAligned(boolean includeHidden); /** + * Answers if the sequence at alignmentIndex is hidden + * + * @param alignmentIndex + * the index to check + * @return true if the sequence is hidden + */ + boolean isHidden(int alignmentIndex); + + /** * Gets sequences as a Synchronized collection * * @return All sequences in alignment. @@ -90,6 +108,17 @@ public interface AlignmentI extends AnnotatedCollectionI SequenceI getSequenceAt(int i); /** + * Find a specific sequence in this alignment. + * + * @param i + * Index of required sequence in full alignment, i.e. if all columns + * were visible + * + * @return SequenceI at given index. + */ + SequenceI getSequenceAtAbsoluteIndex(int i); + + /** * Returns a map of lists of sequences keyed by sequence name. * * @return @@ -118,7 +147,9 @@ public interface AlignmentI extends AnnotatedCollectionI SequenceI replaceSequenceAt(int i, SequenceI seq); /** - * Deletes a sequence from the alignment + * Deletes a sequence from the alignment. Updates hidden sequences to account + * for the removed sequence. Do NOT use this method to delete sequences which + * are just hidden. * * @param s * Sequence to be deleted. @@ -126,7 +157,9 @@ public interface AlignmentI extends AnnotatedCollectionI void deleteSequence(SequenceI s); /** - * Deletes a sequence from the alignment. + * Deletes a sequence from the alignment. Updates hidden sequences to account + * for the removed sequence. Do NOT use this method to delete sequences which + * are just hidden. * * @param i * Index of sequence to be deleted. @@ -134,6 +167,14 @@ public interface AlignmentI extends AnnotatedCollectionI void deleteSequence(int i); /** + * Deletes a sequence in the alignment which has been hidden. + * + * @param i + * Index of sequence to be deleted + */ + void deleteHiddenSequence(int i); + + /** * Finds sequence in alignment using sequence name as query. * * @param name @@ -545,4 +586,5 @@ public interface AlignmentI extends AnnotatedCollectionI * @return */ public int[] getVisibleStartAndEndIndex(List hiddenCols); + } diff --git a/src/jalview/datamodel/ColumnSelection.java b/src/jalview/datamodel/ColumnSelection.java index 98a7fe2..97bc5a3 100644 --- a/src/jalview/datamodel/ColumnSelection.java +++ b/src/jalview/datamodel/ColumnSelection.java @@ -690,8 +690,8 @@ public class ColumnSelection * left-most visible column will always be returned. * * @param hiddenColumn - * int - * @return int + * the column index in the full alignment including hidden columns + * @return the position of the column in the visible alignment */ public int findColumnPosition(int hiddenColumn) { @@ -708,15 +708,89 @@ public class ColumnSelection result -= region[1] + 1 - region[0]; } } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size())); - if (hiddenColumn > region[0] && hiddenColumn < region[1]) - { - return region[0] + hiddenColumn - result; + + if (hiddenColumn >= region[0] && hiddenColumn <= region[1]) + { + // Here the hidden column is within a region, so + // we want to return the position of region[0]-1, adjusted for any + // earlier hidden columns. + // Calculate the difference between the actual hidden col position + // and region[0]-1, and then subtract from result to convert result from + // the adjusted hiddenColumn value to the adjusted region[0]-1 value + + // However, if the region begins at 0 we cannot return region[0]-1 + // just return 0 + if (region[0] == 0) + { + return 0; + } + else + { + return result - (hiddenColumn - region[0] + 1); + } } } return result; // return the shifted position after removing hidden columns. } /** + * Find the visible column which is a given visible number of columns to the + * left of another visible column. i.e. for a startColumn x, the column which + * is distance 1 away will be column x-1. + * + * @param visibleDistance + * the number of visible columns to offset by + * @param startColumn + * the column to start from + * @return the position of the column in the visible alignment + */ + public int subtractVisibleColumns(int visibleDistance, int startColumn) + { + int distance = visibleDistance; + + // in case startColumn is in a hidden region, move it to the left + int start = adjustForHiddenColumns(findColumnPosition(startColumn)); + + // get index of hidden region to left of start + int index = getHiddenIndexLeft(start); + if (index == -1) + { + // no hidden regions to left of startColumn + return start - distance; + } + + // walk backwards through the alignment subtracting the counts of visible + // columns from distance + int[] region; + int gap = 0; + int nextstart = start; + + while ((index > -1) && (distance - gap > 0)) + { + // subtract the gap to right of region from distance + distance -= gap; + start = nextstart; + + // calculate the next gap + region = hiddenColumns.get(index); + gap = start - region[1]; + + // set start to just to left of current region + nextstart = region[0] - 1; + index--; + } + + if (distance - gap > 0) + { + // fell out of loop because there are no more hidden regions + distance -= gap; + return nextstart - distance; + } + return start - distance; + + } + + /** * Use this method to determine where the next hiddenRegion starts * * @param hiddenRegion @@ -805,6 +879,35 @@ public class ColumnSelection } + /** + * This method returns the index of the hidden region to the left of a column + * position. If the column is in a hidden region it returns the index of the + * region to the left. If there is no hidden region to the left it returns -1. + * + * @param pos + * int + */ + private int getHiddenIndexLeft(int pos) + { + if (hiddenColumns != null) + { + int index = hiddenColumns.size() - 1; + do + { + int[] region = hiddenColumns.elementAt(index); + if (pos > region[1]) + { + return index; + } + + index--; + } while (index > -1); + } + + return -1; + + } + public void hideSelectedColumns() { synchronized (selection) diff --git a/src/jalview/datamodel/HiddenSequences.java b/src/jalview/datamodel/HiddenSequences.java index 9e2cf72..6950c28 100755 --- a/src/jalview/datamodel/HiddenSequences.java +++ b/src/jalview/datamodel/HiddenSequences.java @@ -154,8 +154,8 @@ public class HiddenSequences hiddenSequences = new SequenceI[alignment.getHeight()]; } - int alignmentIndex = alignment.findIndex(sequence); - alignmentIndex = adjustForHiddenSeqs(alignmentIndex); + int absAlignmentIndex = alignment.findIndex(sequence); + int alignmentIndex = adjustForHiddenSeqs(absAlignmentIndex); if (hiddenSequences[alignmentIndex] != null) { @@ -164,7 +164,7 @@ public class HiddenSequences hiddenSequences[alignmentIndex] = sequence; - alignment.deleteSequence(sequence); + alignment.deleteHiddenSequence(absAlignmentIndex); } public List showAll( @@ -246,6 +246,12 @@ public class HiddenSequences return hiddenSequences == null ? null : hiddenSequences[alignmentIndex]; } + /** + * Convert absolute alignment index to visible alignment index + * + * @param alignmentIndex + * @return + */ public int findIndexWithoutHiddenSeqs(int alignmentIndex) { if (hiddenSequences == null) @@ -254,8 +260,14 @@ public class HiddenSequences } int index = 0; int hiddenSeqs = 0; + int diff = 0; if (hiddenSequences.length <= alignmentIndex) { + // if the alignmentIndex runs past the end of hidden sequences + // and therefore actually past the end of the alignment + // store the difference to add back on at the end, so that behaviour + // is consistent with hidden columns behaviour (used by overview panel) + diff = alignmentIndex - hiddenSequences.length + 1; alignmentIndex = hiddenSequences.length - 1; } @@ -268,9 +280,50 @@ public class HiddenSequences index++; } - return (alignmentIndex - hiddenSeqs); + return (alignmentIndex - hiddenSeqs + diff); + } + + /** + * Find the visible row which is a given visible number of rows above another + * visible row. i.e. for a startRow x, the row which is distance 1 away will + * be row x-1. + * + * @param visibleDistance + * the number of visible rows to offset by + * @param startRow + * the row to start from + * @return the position of the row in the visible alignment + */ + public int subtractVisibleRows(int visibleDistance, int startRow) + { + // walk upwards through the alignment + // count all the non-null sequences until we have visibleDistance counted + // then return the next visible sequence + if (hiddenSequences == null) + { + return startRow - visibleDistance; + } + + int index = startRow; + int count = 0; + while ((index > -1) && (count < visibleDistance)) + { + if (hiddenSequences[index] == null) + { + // count visible sequences + count++; + } + index--; + } + return index; } + /** + * Convert alignment index from visible alignment to absolute alignment + * + * @param alignmentIndex + * @return + */ public int adjustForHiddenSeqs(int alignmentIndex) { if (hiddenSequences == null) diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index b5fc817..ab1ac0e 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -86,6 +86,7 @@ import jalview.schemes.ResidueProperties; import jalview.schemes.TCoffeeColourScheme; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import jalview.ws.DBRefFetcher; import jalview.ws.DBRefFetcher.FetchFinishedListenerI; import jalview.ws.jws1.Discoverer; @@ -160,6 +161,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, AlignViewport viewport; + ViewportRanges vpRanges; + public AlignViewControllerI avc; List alignPanels = new ArrayList(); @@ -331,6 +334,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, progressBar = new ProgressBar(this.statusPanel, this.statusBar); } + vpRanges = viewport.getRanges(); avc = new jalview.controller.AlignViewController(this, viewport, alignPanel); if (viewport.getAlignmentConservationAnnotation() == null) @@ -640,8 +644,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, new String[] { (viewport.cursorMode ? "on" : "off") })); if (viewport.cursorMode) { - alignPanel.getSeqPanel().seqCanvas.cursorX = viewport.startRes; - alignPanel.getSeqPanel().seqCanvas.cursorY = viewport.startSeq; + alignPanel.getSeqPanel().seqCanvas.cursorX = vpRanges + .getStartRes(); + alignPanel.getSeqPanel().seqCanvas.cursorY = vpRanges + .getStartSeq(); } alignPanel.getSeqPanel().seqCanvas.repaint(); break; @@ -679,8 +685,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } else { - alignPanel.setScrollValues(viewport.startRes, viewport.startSeq - - viewport.endSeq + viewport.startSeq); + alignPanel.setScrollValues(vpRanges.getStartRes(), + 2 * vpRanges.getStartSeq() - vpRanges.getEndSeq()); } break; case KeyEvent.VK_PAGE_DOWN: @@ -690,8 +696,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } else { - alignPanel.setScrollValues(viewport.startRes, viewport.startSeq - + viewport.endSeq - viewport.startSeq); + alignPanel.setScrollValues(vpRanges.getStartRes(), + vpRanges.getEndSeq()); } break; } @@ -2141,7 +2147,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { // propagate alignment changed. - viewport.setEndSeq(alignment.getHeight()); + vpRanges.setEndSeq(alignment.getHeight()); if (annotationAdded) { // Duplicate sequence annotation in all views. @@ -2545,7 +2551,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { trimRegion = new TrimRegionCommand("Remove Left", true, seqs, column, viewport.getAlignment()); - viewport.setStartRes(0); + vpRanges.setStartRes(0); } else { @@ -2612,13 +2618,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // This is to maintain viewport position on first residue // of first sequence SequenceI seq = viewport.getAlignment().getSequenceAt(0); - int startRes = seq.findPosition(viewport.startRes); + int startRes = seq.findPosition(vpRanges.getStartRes()); // ShiftList shifts; // viewport.getAlignment().removeGaps(shifts=new ShiftList()); // edit.alColumnChanges=shifts.getInverse(); // if (viewport.hasHiddenColumns) // viewport.getColumnSelection().compensateForEdits(shifts); - viewport.setStartRes(seq.findIndex(startRes) - 1); + vpRanges.setStartRes(seq.findIndex(startRes) - 1); viewport.firePropertyChange("alignment", null, viewport.getAlignment() .getSequences()); @@ -2651,12 +2657,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // This is to maintain viewport position on first residue // of first sequence SequenceI seq = viewport.getAlignment().getSequenceAt(0); - int startRes = seq.findPosition(viewport.startRes); + int startRes = seq.findPosition(vpRanges.getStartRes()); addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end, viewport.getAlignment())); - viewport.setStartRes(seq.findIndex(startRes) - 1); + vpRanges.setStartRes(seq.findIndex(startRes) - 1); viewport.firePropertyChange("alignment", null, viewport.getAlignment() .getSequences()); diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index e0efa7c..602e3a1 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -46,12 +46,12 @@ import jalview.schemes.ColourSchemeI; import jalview.schemes.ColourSchemeProperty; import jalview.schemes.ResidueColourScheme; import jalview.schemes.UserColourScheme; -import jalview.structure.CommandListener; import jalview.structure.SelectionSource; import jalview.structure.StructureSelectionManager; import jalview.structure.VamsasSource; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import jalview.ws.params.AutoCalcSetting; import java.awt.Container; @@ -72,7 +72,7 @@ import javax.swing.JInternalFrame; * @version $Revision: 1.141 $ */ public class AlignViewport extends AlignmentViewport implements - SelectionSource, CommandListener + SelectionSource { Font font; @@ -238,10 +238,7 @@ public class AlignViewport extends AlignmentViewport implements void init() { - this.startRes = 0; - this.endRes = alignment.getWidth() - 1; - this.startSeq = 0; - this.endSeq = alignment.getHeight() - 1; + ranges = new ViewportRanges(this.alignment); applyViewProperties(); String fontName = Cache.getDefault("FONT_NAME", "SansSerif"); @@ -855,7 +852,7 @@ public class AlignViewport extends AlignmentViewport implements } } - setEndSeq(getAlignment().getHeight()); + ranges.setEndSeq(getAlignment().getHeight()); firePropertyChange("alignment", null, getAlignment().getSequences()); } diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index e61b042..ac137b9 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -35,6 +35,7 @@ import jalview.schemes.ResidueProperties; import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.util.Platform; +import jalview.viewmodel.ViewportRanges; import java.awt.BorderLayout; import java.awt.Color; @@ -69,6 +70,8 @@ public class AlignmentPanel extends GAlignmentPanel implements { public AlignViewport av; + ViewportRanges vpRanges; + OverviewPanel overviewPanel; private SeqPanel seqPanel; @@ -91,9 +94,9 @@ public class AlignmentPanel extends GAlignmentPanel implements // this value is set false when selection area being dragged boolean fastPaint = true; - int hextent = 0; + private int hextent = 0; - int vextent = 0; + private int vextent = 0; /* * Flag set while scrolling to follow complementary cDNA/protein scroll. When @@ -113,6 +116,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { alignFrame = af; this.av = av; + vpRanges = av.getRanges(); setSeqPanel(new SeqPanel(av, this)); setIdPanel(new IdPanel(av, this)); @@ -377,7 +381,7 @@ public class AlignmentPanel extends GAlignmentPanel implements */ if (centre) { - int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1; + int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1; start = Math.max(start - offset, 0); end = end + offset - 1; } @@ -413,7 +417,7 @@ public class AlignmentPanel extends GAlignmentPanel implements // + av.getStartSeq() + ", ends=" + av.getEndSeq()); if (!av.getWrapAlignment()) { - if ((startv = av.getStartRes()) >= start) + if ((startv = vpRanges.getStartRes()) >= start) { /* * Scroll left to make start of search results visible @@ -421,7 +425,7 @@ public class AlignmentPanel extends GAlignmentPanel implements // setScrollValues(start - 1, seqIndex); // plus one residue setScrollValues(start, seqIndex); } - else if ((endv = av.getEndRes()) <= end) + else if ((endv = vpRanges.getEndRes()) <= end) { /* * Scroll right to make end of search results visible @@ -429,19 +433,20 @@ public class AlignmentPanel extends GAlignmentPanel implements // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one setScrollValues(startv + end - endv, seqIndex); } - else if ((starts = av.getStartSeq()) > seqIndex) + else if ((starts = vpRanges.getStartSeq()) > seqIndex) { /* * Scroll up to make start of search results visible */ - setScrollValues(av.getStartRes(), seqIndex); + setScrollValues(vpRanges.getStartRes(), seqIndex); } - else if ((ends = av.getEndSeq()) <= seqIndex) + else if ((ends = vpRanges.getEndSeq()) <= seqIndex) { /* * Scroll down to make end of search results visible */ - setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); + setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends + + 1); } /* * Else results are already visible - no need to scroll @@ -464,10 +469,11 @@ public class AlignmentPanel extends GAlignmentPanel implements { int cwidth = getSeqPanel().seqCanvas .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth)) + if (res < vpRanges.getStartRes() + || res >= (vpRanges.getStartRes() + cwidth)) { vscroll.setValue((res / cwidth)); - av.startRes = vscroll.getValue() * cwidth; + vpRanges.setStartRes(vscroll.getValue() * cwidth); } } @@ -591,7 +597,7 @@ public class AlignmentPanel extends GAlignmentPanel implements fontChanged(); setAnnotationVisible(av.isShowAnnotation()); boolean wrap = av.getWrapAlignment(); - av.startSeq = 0; + vpRanges.setStartSeq(0); scalePanelHolder.setVisible(!wrap); hscroll.setVisible(!wrap); idwidthAdjuster.setVisible(!wrap); @@ -688,7 +694,6 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public void setScrollValues(int x, int y) { - // System.err.println("Scroll " + this.av.viewName + " to " + x + "," + y); if (av == null || av.getAlignment() == null) { return; @@ -698,12 +703,10 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { + // reset the width to exclude hidden columns width = av.getColumnSelection().findColumnPosition(width); } - av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av - .getCharWidth())) - 1); - hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); @@ -737,6 +740,10 @@ public class AlignmentPanel extends GAlignmentPanel implements x = 0; } + // update endRes after x has (possibly) been adjusted + vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av + .getCharWidth())) - 1); + /* * each scroll adjustment triggers adjustmentValueChanged, which resets the * 'do not scroll complement' flag; ensure it is the same for both @@ -757,14 +764,14 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public void adjustmentValueChanged(AdjustmentEvent evt) { - int oldX = av.getStartRes(); - int oldY = av.getStartSeq(); + int oldX = vpRanges.getStartRes(); + int oldY = vpRanges.getStartSeq(); if (evt.getSource() == hscroll) { int x = hscroll.getValue(); - av.setStartRes(x); - av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av + vpRanges.setStartRes(x); + vpRanges.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av .getCharWidth())) - 1); } @@ -778,8 +785,8 @@ public class AlignmentPanel extends GAlignmentPanel implements { int rowSize = getSeqPanel().seqCanvas .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - av.setStartRes(offy * rowSize); - av.setEndRes((offy + 1) * rowSize); + vpRanges.setStartRes(offy * rowSize); + vpRanges.setEndRes((offy + 1) * rowSize); } else { @@ -791,16 +798,18 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public void run() { - setScrollValues(av.getStartRes(), av.getStartSeq()); + setScrollValues(vpRanges.getStartRes(), + vpRanges.getStartSeq()); } }); } } else { - av.setStartSeq(offy); - av.setEndSeq(offy - + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight())); + vpRanges.setStartSeq(offy); + vpRanges.setEndSeq(offy + + (getSeqPanel().seqCanvas.getHeight() / av.getCharHeight()) + - 1); } } @@ -809,8 +818,8 @@ public class AlignmentPanel extends GAlignmentPanel implements overviewPanel.setBoxPosition(); } - int scrollX = av.startRes - oldX; - int scrollY = av.startSeq - oldY; + int scrollX = vpRanges.getStartRes() - oldX; + int scrollY = vpRanges.getStartSeq() - oldY; if (av.getWrapAlignment() || !fastPaint) { @@ -820,13 +829,13 @@ public class AlignmentPanel extends GAlignmentPanel implements { // Make sure we're not trying to draw a panel // larger than the visible window - if (scrollX > av.endRes - av.startRes) + if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes()) { - scrollX = av.endRes - av.startRes; + scrollX = vpRanges.getEndRes() - vpRanges.getStartRes(); } - else if (scrollX < av.startRes - av.endRes) + else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes()) { - scrollX = av.startRes - av.endRes; + scrollX = vpRanges.getStartRes() - vpRanges.getEndRes(); } if (scrollX != 0 || scrollY != 0) @@ -926,7 +935,7 @@ public class AlignmentPanel extends GAlignmentPanel implements } else { - setScrollValues(av.getStartRes(), av.getStartSeq()); + setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq()); } } diff --git a/src/jalview/gui/AnnotationPanel.java b/src/jalview/gui/AnnotationPanel.java index b1f0edb..84f3e6c 100755 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@ -55,7 +55,6 @@ import java.util.List; import javax.swing.JColorChooser; import javax.swing.JMenuItem; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.Scrollable; @@ -708,7 +707,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, return; } - int column = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int column = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); if (av.hasHiddenColumns()) { @@ -905,7 +905,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, return; } } - imgWidth = (av.endRes - av.startRes + 1) * av.getCharWidth(); + imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes() + 1) + * av.getCharWidth(); if (imgWidth < 1) { return; @@ -946,7 +947,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, imageFresh = true; } - drawComponent(gg, av.startRes, av.endRes + 1); + drawComponent(gg, av.getRanges().getStartRes(), av.getRanges() + .getEndRes() + 1); imageFresh = false; g.drawImage(image, 0, 0, this); } @@ -976,8 +978,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.getCharWidth(), 0); long mtime = System.currentTimeMillis(); - int sr = av.startRes; - int er = av.endRes + 1; + int sr = av.getRanges().getStartRes(); + int er = av.getRanges().getEndRes() + 1; int transX = 0; if (horizontal > 0) // scrollbar pulled right, image to the left diff --git a/src/jalview/gui/IdCanvas.java b/src/jalview/gui/IdCanvas.java index 37be8bc..aad0776 100755 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@ -21,6 +21,7 @@ package jalview.gui; import jalview.datamodel.SequenceI; +import jalview.viewmodel.ViewportRanges; import java.awt.BorderLayout; import java.awt.Color; @@ -158,33 +159,35 @@ public class IdCanvas extends JPanel return; } + ViewportRanges ranges = av.getRanges(); + gg.copyArea(0, 0, getWidth(), imgHeight, 0, -vertical * av.getCharHeight()); - int ss = av.startSeq; - int es = av.endSeq; + int ss = ranges.getStartSeq(); + int es = ranges.getEndSeq(); int transY = 0; if (vertical > 0) // scroll down { ss = es - vertical; - if (ss < av.startSeq) + if (ss < ranges.getStartSeq()) { // ie scrolling too fast, more than a page at a time - ss = av.startSeq; + ss = ranges.getStartSeq(); } else { - transY = imgHeight - (vertical * av.getCharHeight()); + transY = imgHeight - ((vertical + 1) * av.getCharHeight()); } } - else if (vertical < 0) + else if (vertical < 0) // scroll up { es = ss - vertical; - if (es > av.endSeq) + if (es > ranges.getEndSeq()) { - es = av.endSeq; + es = ranges.getEndSeq(); } } @@ -240,7 +243,7 @@ public class IdCanvas extends JPanel gg.setColor(Color.white); gg.fillRect(0, 0, getWidth(), imgHeight); - drawIds(av.getStartSeq(), av.endSeq); + drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq()); g.drawImage(image, 0, 0, this); } @@ -314,10 +317,11 @@ public class IdCanvas extends JPanel int cHeight = alheight * av.getCharHeight() + hgap + annotationHeight; - int rowSize = av.getEndRes() - av.getStartRes(); + int rowSize = av.getRanges().getEndRes() + - av.getRanges().getStartRes(); // Draw the rest of the panels - for (int ypos = hgap, row = av.startRes; (ypos <= getHeight()) + for (int ypos = hgap, row = av.getRanges().getStartRes(); (ypos <= getHeight()) && (row < maxwidth); ypos += cHeight, row += rowSize) { for (int i = starty; i < alheight; i++) @@ -354,7 +358,7 @@ public class IdCanvas extends JPanel SequenceI sequence; // Now draw the id strings - for (int i = starty; i < endy; i++) + for (int i = starty; i <= endy; i++) { sequence = av.getAlignment().getSequenceAt(i); diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index 6ae19f0..2074900 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -242,13 +242,14 @@ public class IdPanel extends JPanel implements MouseListener, return; } - if (mouseDragging && (e.getY() < 0) && (av.getStartSeq() > 0)) + if (mouseDragging && (e.getY() < 0) + && (av.getRanges().getStartSeq() > 0)) { scrollThread = new ScrollThread(true); } if (mouseDragging && (e.getY() >= getHeight()) - && (av.getAlignment().getHeight() > av.getEndSeq())) + && (av.getAlignment().getHeight() > av.getRanges().getEndSeq())) { scrollThread = new ScrollThread(false); } @@ -442,9 +443,10 @@ public class IdPanel extends JPanel implements MouseListener, int index = av.getAlignment().findIndex(list.get(0)); // do we need to scroll the panel? - if ((av.getStartSeq() > index) || (av.getEndSeq() < index)) + if ((av.getRanges().getStartSeq() > index) + || (av.getRanges().getEndSeq() < index)) { - alignPanel.setScrollValues(av.getStartRes(), index); + alignPanel.setScrollValues(av.getRanges().getStartRes(), index); } } @@ -486,11 +488,11 @@ public class IdPanel extends JPanel implements MouseListener, if (alignPanel.scrollUp(up)) { // scroll was ok, so add new sequence to selection - int seq = av.getStartSeq(); + int seq = av.getRanges().getStartSeq(); if (!up) { - seq = av.getEndSeq(); + seq = av.getRanges().getEndSeq(); } if (seq < lastid) diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 3ac453f..e8b832d 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -87,6 +87,7 @@ import jalview.util.Platform; import jalview.util.StringUtils; import jalview.util.jarInputStreamProvider; import jalview.viewmodel.AlignmentViewport; +import jalview.viewmodel.ViewportRanges; import jalview.viewmodel.seqfeatures.FeatureRendererSettings; import jalview.viewmodel.seqfeatures.FeaturesDisplayed; import jalview.ws.jws2.Jws2Discoverer; @@ -755,6 +756,7 @@ public class Jalview2XML List userColours = new ArrayList(); AlignViewport av = ap.av; + ViewportRanges vpRanges = av.getRanges(); JalviewModel object = new JalviewModel(); object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel()); @@ -1270,8 +1272,8 @@ public class Jalview2XML view.setWidth(size.width); view.setHeight(size.height); - view.setStartRes(av.startRes); - view.setStartSeq(av.startSeq); + view.setStartRes(vpRanges.getStartRes()); + view.setStartSeq(vpRanges.getStartSeq()); if (av.getGlobalColourScheme() instanceof jalview.schemes.UserColourScheme) { @@ -4448,8 +4450,8 @@ public class Jalview2XML af.viewport.setThresholdTextColour(view.getTextColThreshold()); af.viewport.setShowUnconserved(view.hasShowUnconserved() ? view .isShowUnconserved() : false); - af.viewport.setStartRes(view.getStartRes()); - af.viewport.setStartSeq(view.getStartSeq()); + af.viewport.getRanges().setStartRes(view.getStartRes()); + af.viewport.getRanges().setStartSeq(view.getStartSeq()); af.alignPanel.updateLayout(); ColourSchemeI cs = null; // apply colourschemes diff --git a/src/jalview/gui/Jalview2XML_V1.java b/src/jalview/gui/Jalview2XML_V1.java index e751a2c..6235cbe 100755 --- a/src/jalview/gui/Jalview2XML_V1.java +++ b/src/jalview/gui/Jalview2XML_V1.java @@ -367,8 +367,8 @@ public class Jalview2XML_V1 af.setBounds(view.getXpos(), view.getYpos(), view.getWidth(), view.getHeight()); - af.viewport.setStartRes(view.getStartRes()); - af.viewport.setStartSeq(view.getStartSeq()); + af.viewport.getRanges().setStartRes(view.getStartRes()); + af.viewport.getRanges().setStartSeq(view.getStartSeq()); af.viewport.setShowAnnotation(view.getShowAnnotation()); af.viewport.setAbovePIDThreshold(view.getPidSelected()); af.viewport.setColourText(view.getShowColourText()); diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index 4097c40..ac2138f 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -20,8 +20,10 @@ */ package jalview.gui; +import jalview.datamodel.SequenceI; import jalview.renderer.AnnotationRenderer; import jalview.renderer.seqfeatures.FeatureColourFinder; +import jalview.viewmodel.OverviewDimensions; import java.awt.Color; import java.awt.Dimension; @@ -36,57 +38,51 @@ import java.awt.image.BufferedImage; import javax.swing.JPanel; /** - * DOCUMENT ME! + * Panel displaying an overview of the full alignment, with an interactive box + * representing the viewport onto the alignment. * * @author $author$ * @version $Revision$ */ public class OverviewPanel extends JPanel implements Runnable { - BufferedImage miniMe; + private static final Color TRANS_GREY = new Color(100, 100, 100, 25); - AlignViewport av; + private final AnnotationRenderer renderer = new AnnotationRenderer(); - AlignmentPanel ap; + private OverviewDimensions od; - final AnnotationRenderer renderer = new AnnotationRenderer(); + private BufferedImage miniMe; - float scalew = 1f; - - float scaleh = 1f; - - int width; - - int sequencesHeight; - - int graphHeight = 20; - - int boxX = -1; + private BufferedImage lastMiniMe = null; - int boxY = -1; + private AlignViewport av; - int boxWidth = -1; + private AlignmentPanel ap; - int boxHeight = -1; + // + private boolean resizing = false; - boolean resizing = false; + // This is set true if the user resizes whilst + // the overview is being calculated + private boolean resizeAgain = false; // Can set different properties in this seqCanvas than // main visible SeqCanvas - SequenceRenderer sr; + private SequenceRenderer sr; jalview.renderer.seqfeatures.FeatureRenderer fr; /** * Creates a new OverviewPanel object. * - * @param ap - * DOCUMENT ME! + * @param alPanel + * The alignment panel which is shown in the overview panel */ - public OverviewPanel(AlignmentPanel ap) + public OverviewPanel(AlignmentPanel alPanel) { - this.av = ap.av; - this.ap = ap; + this.av = alPanel.av; + this.ap = alPanel; setLayout(null); sr = new SequenceRenderer(av); @@ -94,44 +90,15 @@ public class OverviewPanel extends JPanel implements Runnable sr.forOverview = true; fr = new FeatureRenderer(ap); - // scale the initial size of overviewpanel to shape of alignment - float initialScale = (float) av.getAlignment().getWidth() - / (float) av.getAlignment().getHeight(); - - if (av.getAlignmentConservationAnnotation() == null) - { - graphHeight = 0; - } - - if (av.getAlignment().getWidth() > av.getAlignment().getHeight()) - { - // wider - width = 400; - sequencesHeight = (int) (400f / initialScale); - if (sequencesHeight < 40) - { - sequencesHeight = 40; - } - } - else - { - // taller - width = (int) (400f * initialScale); - sequencesHeight = 300; - - if (width < 120) - { - width = 120; - } - } + od = new OverviewDimensions(av.getRanges(), av.isShowAnnotation()); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent evt) { - if ((getWidth() != width) - || (getHeight() != (sequencesHeight + graphHeight))) + if ((getWidth() != od.getWidth()) + || (getHeight() != (od.getHeight()))) { updateOverviewImage(); } @@ -145,11 +112,10 @@ public class OverviewPanel extends JPanel implements Runnable { if (!av.getWrapAlignment()) { - // TODO: feature: jv2.5 detect shift drag and update selection from - // it. - boxX = evt.getX(); - boxY = evt.getY(); - checkValid(); + od.updateViewportFromMouse(evt.getX(), evt.getY(), av + .getAlignment().getHiddenSequences(), av + .getColumnSelection(), av.getRanges()); + ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); } } }); @@ -161,9 +127,10 @@ public class OverviewPanel extends JPanel implements Runnable { if (!av.getWrapAlignment()) { - boxX = evt.getX(); - boxY = evt.getY(); - checkValid(); + od.updateViewportFromMouse(evt.getX(), evt.getY(), av + .getAlignment().getHiddenSequences(), av + .getColumnSelection(), av.getRanges()); + ap.setScrollValues(od.getScrollCol(), od.getScrollRow()); } } }); @@ -172,60 +139,7 @@ public class OverviewPanel extends JPanel implements Runnable } /** - * DOCUMENT ME! - */ - void checkValid() - { - if (boxY < 0) - { - boxY = 0; - } - - if (boxY > (sequencesHeight - boxHeight)) - { - boxY = sequencesHeight - boxHeight + 1; - } - - if (boxX < 0) - { - boxX = 0; - } - - if (boxX > (width - boxWidth)) - { - if (av.hasHiddenColumns()) - { - // Try smallest possible box - boxWidth = (int) ((av.endRes - av.startRes + 1) * av.getCharWidth() * scalew); - } - boxX = width - boxWidth; - } - - int col = (int) (boxX / scalew / av.getCharWidth()); - int row = (int) (boxY / scaleh / av.getCharHeight()); - - if (av.hasHiddenColumns()) - { - if (!av.getColumnSelection().isVisible(col)) - { - return; - } - - col = av.getColumnSelection().findColumnPosition(col); - } - - if (av.hasHiddenRows()) - { - row = av.getAlignment().getHiddenSequences() - .findIndexWithoutHiddenSeqs(row); - } - - ap.setScrollValues(col, row); - - } - - /** - * DOCUMENT ME! + * Updates the overview image when the related alignment panel is updated */ public void updateOverviewImage() { @@ -239,24 +153,17 @@ public class OverviewPanel extends JPanel implements Runnable if ((getWidth() > 0) && (getHeight() > 0)) { - width = getWidth(); - sequencesHeight = getHeight() - graphHeight; + od.setWidth(getWidth()); + od.setHeight(getHeight()); } - setPreferredSize(new Dimension(width, sequencesHeight + graphHeight)); + setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); Thread thread = new Thread(this); thread.start(); repaint(); } - // This is set true if the user resizes whilst - // the overview is being calculated - boolean resizeAgain = false; - - /** - * DOCUMENT ME! - */ @Override public void run() { @@ -267,146 +174,45 @@ public class OverviewPanel extends JPanel implements Runnable fr.transferSettings(ap.getSeqPanel().seqCanvas.getFeatureRenderer()); } - int alwidth = av.getAlignment().getWidth(); - int alheight = av.getAlignment().getHeight() - + av.getAlignment().getHiddenSequences().getSize(); - - setPreferredSize(new Dimension(width, sequencesHeight + graphHeight)); - - int fullsizeWidth = alwidth * av.getCharWidth(); - int fullsizeHeight = alheight * av.getCharHeight(); + // why do we need to set preferred size again? was set in + // updateOverviewImage + setPreferredSize(new Dimension(od.getWidth(), od.getHeight())); - scalew = (float) width / (float) fullsizeWidth; - scaleh = (float) sequencesHeight / (float) fullsizeHeight; - - miniMe = new BufferedImage(width, sequencesHeight + graphHeight, + miniMe = new BufferedImage(od.getWidth(), od.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics mg = miniMe.getGraphics(); mg.setColor(Color.orange); - mg.fillRect(0, 0, width, miniMe.getHeight()); - - float sampleCol = (float) alwidth / (float) width; - float sampleRow = (float) alheight / (float) sequencesHeight; - - int lastcol = -1, lastrow = -1; - Color color = Color.white; - int row, col; - jalview.datamodel.SequenceI seq; - final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av - .hasHiddenColumns(); - boolean hiddenRow = false; - // get hidden row and hidden column map once at beginning. - // clone featureRenderer settings to avoid race conditions... if state is - // updated just need to refresh again - - FeatureColourFinder finder = new FeatureColourFinder(fr); - - for (row = 0; row < sequencesHeight; row++) - { - if (resizeAgain) - { - break; - } - if ((int) (row * sampleRow) == lastrow) - { - // No need to recalculate the colours, - // Just copy from the row above - for (col = 0; col < width; col++) - { - if (resizeAgain) - { - break; - } - miniMe.setRGB(col, row, miniMe.getRGB(col, row - 1)); - } - continue; - } - - lastrow = (int) (row * sampleRow); - - hiddenRow = false; - if (hasHiddenRows) - { - seq = av.getAlignment().getHiddenSequences() - .getHiddenSequence(lastrow); - if (seq == null) - { - int index = av.getAlignment().getHiddenSequences() - .findIndexWithoutHiddenSeqs(lastrow); - - seq = av.getAlignment().getSequenceAt(index); - } - else - { - hiddenRow = true; - } - } - else - { - seq = av.getAlignment().getSequenceAt(lastrow); - } - - if (seq == null) - { - System.out.println(lastrow + " null"); - continue; - } - - for (col = 0; col < width; col++) - { - if (resizeAgain) - { - break; - } - if ((int) (col * sampleCol) == lastcol - && (int) (row * sampleRow) == lastrow) - { - miniMe.setRGB(col, row, color.getRGB()); - continue; - } + mg.fillRect(0, 0, od.getWidth(), miniMe.getHeight()); - lastcol = (int) (col * sampleCol); - - if (seq.getLength() > lastcol) - { - color = sr.getResidueColour(seq, lastcol, finder); - } - else - { - color = Color.WHITE; - } + // calculate sampleCol and sampleRow + // alignment width is max number of residues/bases + // alignment height is number of sequences + int alwidth = av.getAlignment().getWidth(); + int alheight = av.getAlignment().getAbsoluteHeight(); - if (hiddenRow - || (hasHiddenCols && !av.getColumnSelection().isVisible( - lastcol))) - { - color = color.darker().darker(); - } + // sampleCol or sampleRow is the width/height allocated to each residue + // in particular, sometimes we may need more than one row/col of the + // BufferedImage allocated + // sampleCol is how much of a residue to assign to each pixel + // sampleRow is how many sequences to assign to each pixel + float sampleCol = alwidth / (float) od.getWidth(); + float sampleRow = alheight / (float) od.getSequencesHeight(); - miniMe.setRGB(col, row, color.getRGB()); + buildImage(sampleRow, sampleCol); - } - } - - if (av.getAlignmentConservationAnnotation() != null) + if (av.isShowAnnotation()) { renderer.updateFromAlignViewport(av); - for (col = 0; col < width; col++) + for (int col = 0; col < od.getWidth() && !resizeAgain; col++) { - if (resizeAgain) - { - break; - } - lastcol = (int) (col * sampleCol); - { - mg.translate(col, sequencesHeight); - renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(), - av.getAlignmentConservationAnnotation().annotations, - (int) (sampleCol) + 1, graphHeight, - (int) (col * sampleCol), (int) (col * sampleCol) + 1); - mg.translate(-col, -sequencesHeight); - } + mg.translate(col, od.getSequencesHeight()); + renderer.drawGraph(mg, av.getAlignmentConservationAnnotation(), + av.getAlignmentConservationAnnotation().annotations, + (int) (sampleCol) + 1, od.getGraphHeight(), + (int) (col * sampleCol), (int) (col * sampleCol) + 1); + mg.translate(-col, -od.getSequencesHeight()); + } } System.gc(); @@ -426,66 +232,97 @@ public class OverviewPanel extends JPanel implements Runnable setBoxPosition(); } - /** - * DOCUMENT ME! + /* + * Build the overview panel image */ - public void setBoxPosition() + private void buildImage(float sampleRow, float sampleCol) { - int fullsizeWidth = av.getAlignment().getWidth() * av.getCharWidth(); - int fullsizeHeight = (av.getAlignment().getHeight() + av.getAlignment() - .getHiddenSequences().getSize()) - * av.getCharHeight(); + int lastcol = -1; + int lastrow = -1; + int rgbColour = Color.white.getRGB(); - int startRes = av.getStartRes(); - int endRes = av.getEndRes(); + SequenceI seq = null; + FeatureColourFinder finder = new FeatureColourFinder(fr); - if (av.hasHiddenColumns()) + final boolean hasHiddenCols = av.hasHiddenColumns(); + boolean hiddenRow = false; + // get hidden row and hidden column map once at beginning. + // clone featureRenderer settings to avoid race conditions... if state is + // updated just need to refresh again + for (int row = 0; row < od.getSequencesHeight() && !resizeAgain; row++) { - startRes = av.getColumnSelection().adjustForHiddenColumns(startRes); - endRes = av.getColumnSelection().adjustForHiddenColumns(endRes); - } + boolean doCopy = true; + int currentrow = (int) (row * sampleRow); + if (currentrow != lastrow) + { + doCopy = false; - int startSeq = av.startSeq; - int endSeq = av.endSeq; + lastrow = currentrow; - if (av.hasHiddenRows()) - { - startSeq = av.getAlignment().getHiddenSequences() - .adjustForHiddenSeqs(startSeq); + // get the sequence which would be at alignment index 'lastrow' if no + // rows were hidden, and determine whether it is hidden or not + hiddenRow = av.getAlignment().isHidden(lastrow); + seq = av.getAlignment().getSequenceAtAbsoluteIndex(lastrow); + } - endSeq = av.getAlignment().getHiddenSequences() - .adjustForHiddenSeqs(endSeq); + for (int col = 0; col < od.getWidth() && !resizeAgain; col++) + { + if (doCopy) + { + rgbColour = miniMe.getRGB(col, row - 1); + } + else if ((int) (col * sampleCol) != lastcol + || (int) (row * sampleRow) != lastrow) + { + lastcol = (int) (col * sampleCol); + rgbColour = getColumnColourFromSequence(seq, hiddenRow, + hasHiddenCols, lastcol, finder); + } + // else we just use the color we already have , so don't need to set it + miniMe.setRGB(col, row, rgbColour); + } } + } - scalew = (float) width / (float) fullsizeWidth; - scaleh = (float) sequencesHeight / (float) fullsizeHeight; - - boxX = (int) (startRes * av.getCharWidth() * scalew); - boxY = (int) (startSeq * av.getCharHeight() * scaleh); + /* + * Find the colour of a sequence at a specified column position + */ + private int getColumnColourFromSequence( + jalview.datamodel.SequenceI seq, + boolean hiddenRow, boolean hasHiddenCols, int lastcol, + FeatureColourFinder finder) + { + Color color = Color.white; - if (av.hasHiddenColumns()) + if ((seq != null) && (seq.getLength() > lastcol)) { - boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew); + color = sr.getResidueColour(seq, lastcol, finder); } - else + + if (hiddenRow + || (hasHiddenCols && !av.getColumnSelection() + .isVisible(lastcol))) { - boxWidth = (int) ((endRes - startRes + 1) * av.getCharWidth() * scalew); + color = color.darker().darker(); } - boxHeight = (int) ((endSeq - startSeq) * av.getCharHeight() * scaleh); - - repaint(); + return color.getRGB(); } - private BufferedImage lastMiniMe = null; - /** - * DOCUMENT ME! + * Update the overview panel box when the associated alignment panel is + * changed * - * @param g - * DOCUMENT ME! */ + public void setBoxPosition() + { + od.setBoxPosition(av.getAlignment() + .getHiddenSequences(), av.getColumnSelection(), av.getRanges()); + repaint(); + } + + @Override public void paintComponent(Graphics g) { @@ -500,7 +337,7 @@ public class OverviewPanel extends JPanel implements Runnable { g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this); } - g.setColor(new Color(100, 100, 100, 25)); + g.setColor(TRANS_GREY); g.fillRect(0, 0, getWidth(), getHeight()); } else if (lastMiniMe != null) @@ -508,13 +345,12 @@ public class OverviewPanel extends JPanel implements Runnable g.drawImage(lastMiniMe, 0, 0, this); if (lastMiniMe != miniMe) { - g.setColor(new Color(100, 100, 100, 25)); + g.setColor(TRANS_GREY); g.fillRect(0, 0, getWidth(), getHeight()); } } - // TODO: render selected regions + g.setColor(Color.red); - g.drawRect(boxX, boxY, boxWidth, boxHeight); - g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2); + od.drawBox(g); } } diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index 8961f21..de21be6 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -101,7 +101,7 @@ public class ScalePanel extends JPanel implements MouseMotionListener, @Override public void mousePressed(MouseEvent evt) { - int x = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); final int res; if (av.hasHiddenColumns()) @@ -282,7 +282,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener, { mouseDragging = false; - int res = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int res = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); if (av.hasHiddenColumns()) { @@ -337,7 +338,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener, mouseDragging = true; ColumnSelection cs = av.getColumnSelection(); - int res = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int res = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); res = Math.max(0, res); res = cs.adjustForHiddenColumns(res); res = Math.min(res, av.getAlignment().getWidth() - 1); @@ -389,7 +391,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener, return; } - int res = (evt.getX() / av.getCharWidth()) + av.getStartRes(); + int res = (evt.getX() / av.getCharWidth()) + + av.getRanges().getStartRes(); res = av.getColumnSelection().adjustForHiddenColumns(res); @@ -419,7 +422,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener, @Override public void paintComponent(Graphics g) { - drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight()); + drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(), + getWidth(), getHeight()); } // scalewidth will normally be screenwidth, diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 97889af..4557819 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -26,6 +26,7 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; +import jalview.viewmodel.ViewportRanges; import java.awt.BasicStroke; import java.awt.BorderLayout; @@ -279,10 +280,11 @@ public class SeqCanvas extends JComponent gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth, imgHeight, -horizontal * charWidth, -vertical * charHeight); - int sr = av.startRes; - int er = av.endRes; - int ss = av.startSeq; - int es = av.endSeq; + ViewportRanges ranges = av.getRanges(); + int sr = ranges.getStartRes(); + int er = ranges.getEndRes(); + int ss = ranges.getStartSeq(); + int es = ranges.getEndSeq(); int transX = 0; int transY = 0; @@ -300,22 +302,22 @@ public class SeqCanvas extends JComponent { ss = es - vertical; - if (ss < av.startSeq) + if (ss < ranges.getStartSeq()) { // ie scrolling too fast, more than a page at a time - ss = av.startSeq; + ss = ranges.getStartSeq(); } else { - transY = imgHeight - (vertical * charHeight); + transY = imgHeight - ((vertical + 1) * charHeight); } } else if (vertical < 0) { es = ss - vertical; - if (es > av.endSeq) + if (es > ranges.getEndSeq()) { - es = av.endSeq; + es = ranges.getEndSeq(); } } @@ -395,13 +397,15 @@ public class SeqCanvas extends JComponent gg.setColor(Color.white); gg.fillRect(0, 0, imgWidth, imgHeight); + ViewportRanges ranges = av.getRanges(); if (av.getWrapAlignment()) { - drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes); + drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes()); } else { - drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0); + drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), + ranges.getStartSeq(), ranges.getEndSeq(), 0); } g.drawImage(lcimg, 0, 0, this); @@ -503,7 +507,7 @@ public class SeqCanvas extends JComponent av.setWrappedWidth(cWidth); - av.endRes = av.startRes + cWidth; + av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth); int endx; int ypos = hgap; @@ -718,7 +722,7 @@ public class SeqCanvas extends JComponent // / First draw the sequences // /////////////////////////// - for (int i = startSeq; i < endSeq; i++) + for (int i = startSeq; i <= endSeq; i++) { nextSeq = av.getAlignment().getSequenceAt(i); if (nextSeq == null) @@ -802,7 +806,7 @@ public class SeqCanvas extends JComponent int top = -1; int bottom = -1; - for (i = startSeq; i < endSeq; i++) + for (i = startSeq; i <= endSeq; i++) { sx = (group.getStartRes() - startRes) * charWidth; sy = offset + ((i - startSeq) * charHeight); diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 37b4852..db7aa36 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -209,7 +209,7 @@ public class SeqPanel extends JPanel implements MouseListener, } wrappedBlock = y / cHeight; - wrappedBlock += av.getStartRes() / cwidth; + wrappedBlock += av.getRanges().getStartRes() / cwidth; res = wrappedBlock * cwidth + x / av.getCharWidth(); @@ -222,11 +222,11 @@ public class SeqPanel extends JPanel implements MouseListener, // right-hand gutter x = seqCanvas.getX() + seqCanvas.getWidth(); } - res = (x / av.getCharWidth()) + av.getStartRes(); - if (res > av.getEndRes()) + res = (x / av.getCharWidth()) + av.getRanges().getStartRes(); + if (res > av.getRanges().getEndRes()) { // moused off right - res = av.getEndRes(); + res = av.getRanges().getEndRes(); } } @@ -262,7 +262,9 @@ public class SeqPanel extends JPanel implements MouseListener, } else { - seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(), av + seq = Math.min((y / av.getCharHeight()) + + av.getRanges().getStartSeq(), + av .getAlignment().getHeight() - 1); } @@ -385,18 +387,18 @@ public class SeqPanel extends JPanel implements MouseListener, } else { - while (seqCanvas.cursorY < av.startSeq) + while (seqCanvas.cursorY < av.getRanges().getStartSeq()) { ap.scrollUp(true); } - while (seqCanvas.cursorY + 1 > av.endSeq) + while (seqCanvas.cursorY + 1 > av.getRanges().getEndSeq()) { ap.scrollUp(false); } if (!av.getWrapAlignment()) { while (seqCanvas.cursorX < av.getColumnSelection() - .adjustForHiddenColumns(av.startRes)) + .adjustForHiddenColumns(av.getRanges().getStartRes())) { if (!ap.scrollRight(false)) { @@ -404,7 +406,7 @@ public class SeqPanel extends JPanel implements MouseListener, } } while (seqCanvas.cursorX > av.getColumnSelection() - .adjustForHiddenColumns(av.endRes)) + .adjustForHiddenColumns(av.getRanges().getEndRes())) { if (!ap.scrollRight(true)) { @@ -1772,9 +1774,9 @@ public class SeqPanel extends JPanel implements MouseListener, changeStartRes = true; } - if (res < av.getStartRes()) + if (res < av.getRanges().getStartRes()) { - res = av.getStartRes(); + res = av.getRanges().getStartRes(); } if (changeEndRes) @@ -1908,13 +1910,15 @@ public class SeqPanel extends JPanel implements MouseListener, { if (evt != null) { - if (mouseDragging && (evt.getY() < 0) && (av.getStartSeq() > 0)) + if (mouseDragging && (evt.getY() < 0) + && (av.getRanges().getStartSeq() > 0)) { running = ap.scrollUp(true); } if (mouseDragging && (evt.getY() >= getHeight()) - && (av.getAlignment().getHeight() > av.getEndSeq())) + && (av.getAlignment().getHeight() > av.getRanges() + .getEndSeq())) { running = ap.scrollUp(false); } diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 6f84a2e..3a27c7d 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -307,7 +307,7 @@ public class AnnotationRenderer public void updateFromAlignViewport(AlignViewportI av) { charWidth = av.getCharWidth(); - endRes = av.getEndRes(); + endRes = av.getRanges().getEndRes(); charHeight = av.getCharHeight(); hasHiddenColumns = av.hasHiddenColumns(); validCharWidth = av.isValidCharWidth(); diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 94d0dd1..3547757 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -78,6 +78,8 @@ import jalview.workers.StrucConsensusThread; public abstract class AlignmentViewport implements AlignViewportI, CommandListener, VamsasSource { + protected ViewportRanges ranges; + protected ViewStyleI viewStyle = new ViewStyle(); /** @@ -1293,15 +1295,6 @@ public abstract class AlignmentViewport implements AlignViewportI, */ private boolean followHighlight = true; - // TODO private with getters and setters? - public int startRes; - - public int endRes; - - public int startSeq; - - public int endSeq; - /** * Property change listener for changes in alignment * @@ -2672,63 +2665,10 @@ public abstract class AlignmentViewport implements AlignViewportI, this.followHighlight = b; } - public int getStartRes() - { - return startRes; - } - @Override - public int getEndRes() - { - return endRes; - } - - public int getStartSeq() - { - return startSeq; - } - - public void setStartRes(int res) - { - this.startRes = res; - } - - public void setStartSeq(int seq) - { - this.startSeq = seq; - } - - public void setEndRes(int res) - { - if (res > alignment.getWidth() - 1) - { - // log.System.out.println(" Corrected res from " + res + " to maximum " + - // (alignment.getWidth()-1)); - res = alignment.getWidth() - 1; - } - if (res < 0) - { - res = 0; - } - this.endRes = res; - } - - public void setEndSeq(int seq) - { - if (seq > alignment.getHeight()) - { - seq = alignment.getHeight(); - } - if (seq < 0) - { - seq = 0; - } - this.endSeq = seq; - } - - public int getEndSeq() + public ViewportRanges getRanges() { - return endSeq; + return ranges; } /** @@ -2768,7 +2708,8 @@ public abstract class AlignmentViewport implements AlignViewportI, * locate 'middle' column (true middle if an odd number visible, left of * middle if an even number visible) */ - int middleColumn = getStartRes() + (getEndRes() - getStartRes()) / 2; + int middleColumn = ranges.getStartRes() + + (ranges.getEndRes() - ranges.getStartRes()) / 2; final HiddenSequences hiddenSequences = getAlignment() .getHiddenSequences(); @@ -2778,7 +2719,7 @@ public abstract class AlignmentViewport implements AlignViewportI, */ int lastSeq = alignment.getHeight() - 1; List seqMappings = null; - for (int seqNo = getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++) + for (int seqNo = ranges.getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++) { sequence = getAlignment().getSequenceAt(seqNo); if (hiddenSequences != null && hiddenSequences.isHidden(sequence)) diff --git a/src/jalview/viewmodel/OverviewDimensions.java b/src/jalview/viewmodel/OverviewDimensions.java new file mode 100644 index 0000000..43680b5 --- /dev/null +++ b/src/jalview/viewmodel/OverviewDimensions.java @@ -0,0 +1,343 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.viewmodel; + +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenSequences; + +import java.awt.Graphics; + +public class OverviewDimensions +{ + // Default width and height values + private static final int DEFAULT_GRAPH_HEIGHT = 20; + + private static final int MAX_WIDTH = 400; + + private static final int MIN_WIDTH = 120; + + private static final int MIN_SEQ_HEIGHT = 40; + + private static final int MAX_SEQ_HEIGHT = 300; + + // width of the overview panel + private int width; + + // height of sequences part of the overview panel + private int sequencesHeight; + + // height of the graphs part of the overview panel + private int graphHeight = DEFAULT_GRAPH_HEIGHT; + + // dimensions of box outlining current extent of view in alignment panel + // location of left side of box + private int boxX = -1; + + // location of bottom of box + private int boxY = -1; + + // width of box + private int boxWidth = -1; + + // height of box + private int boxHeight = -1; + + // scroll position in viewport corresponding to boxX + private int scrollCol = -1; + + // scroll position in viewport corresponding to boxY + private int scrollRow = -1; + + /** + * Create an OverviewDimensions object + * + * @param ranges + * positional properties of the viewport + * @param showAnnotationPanel + * true if the annotation panel is to be shown, false otherwise + */ + public OverviewDimensions(ViewportRanges ranges, + boolean showAnnotationPanel) + { + // scale the initial size of overviewpanel to shape of alignment + float initialScale = (float) ranges.getAbsoluteAlignmentWidth() + / (float) ranges.getAbsoluteAlignmentHeight(); + + if (!showAnnotationPanel) + { + graphHeight = 0; + } + + if (ranges.getAbsoluteAlignmentWidth() > ranges + .getAbsoluteAlignmentHeight()) + { + // wider + width = MAX_WIDTH; + sequencesHeight = Math.round(MAX_WIDTH / initialScale); + if (sequencesHeight < MIN_SEQ_HEIGHT) + { + sequencesHeight = MIN_SEQ_HEIGHT; + } + } + else + { + // taller + width = Math.round(MAX_WIDTH * initialScale); + sequencesHeight = MAX_SEQ_HEIGHT; + + if (width < MIN_WIDTH) + { + width = MIN_WIDTH; + } + } + } + + /** + * Check box dimensions and scroll positions and correct if necessary + * + * @param mousex + * x position in overview panel + * @param mousey + * y position in overview panel + * @param hiddenSeqs + * hidden sequences + * @param hiddenCols + * hidden columns + * @param ranges + * viewport position properties + */ + public void updateViewportFromMouse(int mousex, int mousey, + HiddenSequences hiddenSeqs, ColumnSelection hiddenCols, + ViewportRanges ranges) + { + int x = mousex; + int y = mousey; + + int alwidth = ranges.getAbsoluteAlignmentWidth(); + int alheight = ranges.getAbsoluteAlignmentHeight(); + + if (x < 0) + { + x = 0; + } + + if (y < 0) + { + y = 0; + } + + // + // Convert x value to residue position + // + + // need to determine where scrollCol should be, given x + // to do this also need to know width of viewport, and some hidden column + // correction + + // convert x to residues - this is an absolute position + int xAsRes = Math.round((float) x * alwidth / width); + + // get viewport width in residues + int vpwidth = ranges.getEndRes() - ranges.getStartRes() + 1; + + // get where x should be when accounting for hidden cols + // if x is in a hidden col region, shift to left - but we still need + // absolute position + // so convert back after getting visible region position + int visXAsRes = hiddenCols.findColumnPosition(xAsRes); + + // check in case we went off the edge of the alignment + int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1); + if (visXAsRes + vpwidth - 1 > visAlignWidth) + { + // went past the end of the alignment, adjust backwards + + // if last position was before the end of the alignment, need to update + if ((scrollCol + vpwidth - 1) < visAlignWidth) + { + visXAsRes = hiddenCols.findColumnPosition(hiddenCols + .subtractVisibleColumns(vpwidth - 1, alwidth - 1)); + } + else + { + visXAsRes = scrollCol; + } + } + + // + // Convert y value to sequence position + // + + // convert y to residues + int yAsSeq = Math.round((float) y * alheight / sequencesHeight); + + // get viewport height in sequences + // add 1 because height includes both endSeq and startSeq + int vpheight = ranges.getEndSeq() - ranges.getStartSeq() + 1; + + // get where y should be when accounting for hidden rows + // if y is in a hidden row region, shift up - but we still need absolute + // position, + // so convert back after getting visible region position + yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs + .findIndexWithoutHiddenSeqs(yAsSeq)); + + // check in case we went off the edge of the alignment + int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight); + int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq); + if (visYAsRes + vpheight - 1 > visAlignHeight) + { + // went past the end of the alignment, adjust backwards + if ((scrollRow + vpheight - 1) < visAlignHeight) + { + visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(hiddenSeqs + .subtractVisibleRows(vpheight - 1, alheight - 1)); + } + else + { + visYAsRes = scrollRow; + } + } + + // update scroll values + scrollCol = visXAsRes; + scrollRow = visYAsRes; + + } + + /** + * Update the overview panel box when the associated alignment panel is + * changed + * + * @param hiddenSeqs + * hidden sequences + * @param hiddenCols + * hidden columns + * @param ranges + * viewport position properties + */ + public void setBoxPosition(HiddenSequences hiddenSeqs, + ColumnSelection hiddenCols, ViewportRanges ranges) + { + int alwidth = ranges.getAbsoluteAlignmentWidth(); + int alheight = ranges.getAbsoluteAlignmentHeight(); + + // work with absolute values of startRes and endRes + int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes()); + int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes()); + + // work with absolute values of startSeq and endSeq + int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq()); + int endSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getEndSeq()); + + // boxX, boxY is the x,y location equivalent to startRes, startSeq + boxX = Math.round((float) startRes * width / alwidth); + boxY = Math.round((float) startSeq * sequencesHeight / alheight); + + // boxWidth is the width in residues translated to pixels + // since the box includes both the start and end residues, add 1 to the + // difference + boxWidth = Math + .round((float) (endRes - startRes + 1) * width / alwidth); + // boxHeight is the height in sequences translated to pixels + boxHeight = Math.round((float) (endSeq - startSeq + 1) + * sequencesHeight + / alheight); + } + + /** + * Draw the overview panel's viewport box on a graphics object + * + * @param g + * the graphics object to draw on + */ + public void drawBox(Graphics g) + { + g.drawRect(boxX, boxY, boxWidth, boxHeight); + g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2); + } + + public int getScrollCol() + { + return scrollCol; + } + + public int getScrollRow() + { + return scrollRow; + } + + // TODO should be removed, when unit test has mock Graphics object available + // to check boxX/boxY + public int getBoxX() + { + return boxX; + } + + // TODO should be removed, when unit test has mock Graphics object available + // to check boxX/boxY + public int getBoxY() + { + return boxY; + } + + // TODO should be removed, when unit test has mock Graphics object available + public int getBoxWidth() + { + return boxWidth; + } + + // TODO should be removed, when unit test has mock Graphics object available + public int getBoxHeight() + { + return boxHeight; + } + + public void setWidth(int w) + { + width = w; + } + + public void setHeight(int h) + { + sequencesHeight = h - graphHeight; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return sequencesHeight + graphHeight; + } + + public int getSequencesHeight() + { + return sequencesHeight; + } + + public int getGraphHeight() + { + return graphHeight; + } +} diff --git a/src/jalview/viewmodel/ViewportProperties.java b/src/jalview/viewmodel/ViewportProperties.java new file mode 100644 index 0000000..246806e --- /dev/null +++ b/src/jalview/viewmodel/ViewportProperties.java @@ -0,0 +1,26 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.viewmodel; + +public abstract class ViewportProperties +{ + +} diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java new file mode 100644 index 0000000..c91d2d9 --- /dev/null +++ b/src/jalview/viewmodel/ViewportRanges.java @@ -0,0 +1,188 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.viewmodel; + +import jalview.datamodel.AlignmentI; + +/** + * Embryonic class which: Supplies and updates viewport properties relating to + * position such as: start and end residues and sequences; ideally will serve + * hidden columns/rows too. Intention also to support calculations for + * positioning, scrolling etc. such as finding the middle of the viewport, + * checking for scrolls off screen + */ +public class ViewportRanges extends ViewportProperties +{ + // start residue of viewport + private int startRes; + + // end residue of viewport + private int endRes; + + // start sequence of viewport + private int startSeq; + + // end sequence of viewport + private int endSeq; + + // alignment + private AlignmentI al; + + /** + * Constructor + * + * @param alignment + * the viewport's alignment + */ + public ViewportRanges(AlignmentI alignment) + { + // initial values of viewport settings + this.startRes = 0; + this.endRes = alignment.getWidth() - 1; + this.startSeq = 0; + this.endSeq = alignment.getHeight() - 1; + this.al = alignment; + } + + /** + * Get alignment width in cols, including hidden cols + */ + public int getAbsoluteAlignmentWidth() + { + return al.getWidth(); + } + + /** + * Get alignment height in rows, including hidden rows + */ + public int getAbsoluteAlignmentHeight() + { + return al.getHeight() + al.getHiddenSequences().getSize(); + } + + /** + * Set first residue visible in the viewport + * + * @param res + * residue position + */ + public void setStartRes(int res) + { + if (res > al.getWidth() - 1) + { + res = al.getWidth() - 1; + } + else if (res < 0) + { + res = 0; + } + this.startRes = res; + } + + /** + * Set last residue visible in the viewport + * + * @param res + * residue position + */ + public void setEndRes(int res) + { + if (res >= al.getWidth()) + { + res = al.getWidth() - 1; + } + else if (res < 0) + { + res = 0; + } + this.endRes = res; + } + + /** + * Set the first sequence visible in the viewport + * + * @param seq + * sequence position + */ + public void setStartSeq(int seq) + { + if (seq > al.getHeight() - 1) + { + seq = al.getHeight() - 1; + } + else if (seq < 0) + { + seq = 0; + } + this.startSeq = seq; + } + + /** + * Set the last sequence visible in the viewport + * + * @param seq + * sequence position + */ + public void setEndSeq(int seq) + { + if (seq >= al.getHeight()) + { + seq = al.getHeight() - 1; + } + else if (seq < 0) + { + seq = 0; + } + this.endSeq = seq; + } + + /** + * Get start residue of viewport + */ + public int getStartRes() + { + return startRes; + } + + /** + * Get end residue of viewport + */ + public int getEndRes() + { + return endRes; + } + + /** + * Get start sequence of viewport + */ + public int getStartSeq() + { + return startSeq; + } + + /** + * Get end sequence of viewport + */ + public int getEndSeq() + { + return endSeq; + } +} diff --git a/src/jalview/ws/DasSequenceFeatureFetcher.java b/src/jalview/ws/DasSequenceFeatureFetcher.java index 676a4b6..4d3dd2f 100644 --- a/src/jalview/ws/DasSequenceFeatureFetcher.java +++ b/src/jalview/ws/DasSequenceFeatureFetcher.java @@ -617,8 +617,8 @@ public class DasSequenceFeatureFetcher } af.getFeatureRenderer().featuresAdded(); - int start = af.getViewport().getStartSeq(); - int end = af.getViewport().getEndSeq(); + int start = af.getViewport().getRanges().getStartSeq(); + int end = af.getViewport().getRanges().getEndSeq(); int index; for (index = start; index < end; index++) { diff --git a/test/jalview/datamodel/AlignmentTest.java b/test/jalview/datamodel/AlignmentTest.java index 7af77f5..68933bd 100644 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@ -27,6 +27,7 @@ import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertSame; import static org.testng.AssertJUnit.assertTrue; +import jalview.analysis.AlignmentGenerator; import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; import jalview.gui.JvOptionPane; import jalview.io.DataSourceType; @@ -1196,4 +1197,67 @@ public class AlignmentTest assertNull(a.findGroup(seq2, 8)); } + @Test(groups = { "Functional" }) + public void testDeleteSequenceByIndex() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI a = gen.generate(20, 15, 123, 5, 5); + + // delete sequence 10, alignment reduced by 1 + int height = a.getAbsoluteHeight(); + a.deleteSequence(10); + assertEquals(a.getAbsoluteHeight(), height - 1); + + // try to delete -ve index, nothing happens + a.deleteSequence(-1); + assertEquals(a.getAbsoluteHeight(), height - 1); + + // try to delete beyond end of alignment, nothing happens + a.deleteSequence(14); + assertEquals(a.getAbsoluteHeight(), height - 1); + } + + @Test(groups = { "Functional" }) + public void testDeleteSequenceBySeq() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI a = gen.generate(20, 15, 123, 5, 5); + + // delete sequence 10, alignment reduced by 1 + int height = a.getAbsoluteHeight(); + SequenceI seq = a.getSequenceAt(10); + a.deleteSequence(seq); + assertEquals(a.getAbsoluteHeight(), height - 1); + + // try to delete non-existent sequence, nothing happens + seq = new Sequence("cds", "GCCTCGGAT"); + assertEquals(a.getAbsoluteHeight(), height - 1); + } + + @Test(groups = { "Functional" }) + public void testDeleteHiddenSequence() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI a = gen.generate(20, 15, 123, 5, 5); + + // delete a sequence which is hidden, check it is NOT removed from hidden + // sequences + int height = a.getAbsoluteHeight(); + SequenceI seq = a.getSequenceAt(2); + a.getHiddenSequences().hideSequence(seq); + assertEquals(a.getHiddenSequences().getSize(), 1); + a.deleteSequence(2); + assertEquals(a.getAbsoluteHeight(), height - 1); + assertEquals(a.getHiddenSequences().getSize(), 1); + + // delete a sequence which is not hidden, check hiddenSequences are not + // affected + a.deleteSequence(10); + assertEquals(a.getAbsoluteHeight(), height - 2); + assertEquals(a.getHiddenSequences().getSize(), 1); + } + } diff --git a/test/jalview/datamodel/ColumnSelectionTest.java b/test/jalview/datamodel/ColumnSelectionTest.java index 1d819c9..4d3f611 100644 --- a/test/jalview/datamodel/ColumnSelectionTest.java +++ b/test/jalview/datamodel/ColumnSelectionTest.java @@ -105,9 +105,97 @@ public class ColumnSelectionTest cs.hideColumns(4, 4); assertEquals(4, cs.findColumnPosition(5)); + // hiding column 4 moves column 4 to position 3 + assertEquals(3, cs.findColumnPosition(4)); + // hiding columns 1 and 2 moves column 5 to column 2 cs.hideColumns(1, 2); assertEquals(2, cs.findColumnPosition(5)); + + // check with > 1 hidden column regions + // where some columns are in the hidden regions + ColumnSelection cs2 = new ColumnSelection(); + cs2.hideColumns(5, 10); + cs2.hideColumns(20, 27); + cs2.hideColumns(40, 44); + + // hiding columns 5-10 and 20-27 moves column 8 to column 4 + assertEquals(4, cs2.findColumnPosition(8)); + + // and moves column 24 to 13 + assertEquals(13, cs2.findColumnPosition(24)); + + // and moves column 28 to 14 + assertEquals(14, cs2.findColumnPosition(28)); + + // and moves column 40 to 25 + assertEquals(25, cs2.findColumnPosition(40)); + + // check when hidden columns start at 0 that the visible column + // is returned as 0 + ColumnSelection cs3 = new ColumnSelection(); + cs3.hideColumns(0, 4); + assertEquals(0, cs3.findColumnPosition(2)); + + } + + /** + * Test the method that finds the visible column position a given distance + * before another column + */ + @Test(groups = { "Functional" }) + public void testFindColumnNToLeft() + { + ColumnSelection cs = new ColumnSelection(); + + // test that without hidden columns, findColumnNToLeft returns + // position n to left of provided position + int pos = cs.subtractVisibleColumns(3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = cs.subtractVisibleColumns(0, 10); + assertEquals(10, pos); + + // overflow to left returns negative number + pos = cs.subtractVisibleColumns(3, 0); + assertEquals(-3, pos); + + // test that with hidden columns to left of result column + // behaviour is the same as above + cs.hideColumns(1, 3); + + // position n to left of provided position + pos = cs.subtractVisibleColumns(3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = cs.subtractVisibleColumns(0, 10); + assertEquals(10, pos); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.subtractVisibleColumns(8, 17); + assertEquals(5, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.subtractVisibleColumns(8, 23); + assertEquals(9, pos); + + // repeat last 2 tests with no hidden columns to left of required position + cs.revealAllHiddenColumns(); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.subtractVisibleColumns(8, 17); + assertEquals(5, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.subtractVisibleColumns(8, 23); + assertEquals(9, pos); + } /** diff --git a/test/jalview/datamodel/HiddenSequencesTest.java b/test/jalview/datamodel/HiddenSequencesTest.java index cae3536..7795988 100644 --- a/test/jalview/datamodel/HiddenSequencesTest.java +++ b/test/jalview/datamodel/HiddenSequencesTest.java @@ -49,7 +49,7 @@ public class HiddenSequencesTest JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } - static int SEQ_COUNT = 10; + static int SEQ_COUNT = 25; SequenceI[] seqs; @@ -62,8 +62,9 @@ public class HiddenSequencesTest seqs = new SequenceI[SEQ_COUNT]; for (int i = 0; i < SEQ_COUNT; i++) { - // sequence lengths are 1, 2, ... 10 - seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1)); + // sequence lengths are 1, 2, ... 25 + seqs[i] = new Sequence("Seq" + i, + "abcdefghijklmnopqrstuvwxy".substring(0, i + 1)); } } @@ -89,7 +90,7 @@ public class HiddenSequencesTest /* * alignment is now seq0/2/3/4/7/8/9 */ - assertEquals(7, al.getHeight()); + assertEquals(SEQ_COUNT - 3, al.getHeight()); assertEquals(0, hs.adjustForHiddenSeqs(0)); assertEquals(2, hs.adjustForHiddenSeqs(1)); assertEquals(3, hs.adjustForHiddenSeqs(2)); @@ -193,7 +194,7 @@ public class HiddenSequencesTest /* * alignment is now seq0/2/3/4/7/8/9 */ - assertEquals(7, al.getHeight()); + assertEquals(SEQ_COUNT - 3, al.getHeight()); assertEquals(0, hs.findIndexWithoutHiddenSeqs(0)); assertEquals(0, hs.findIndexWithoutHiddenSeqs(1)); assertEquals(1, hs.findIndexWithoutHiddenSeqs(2)); @@ -207,6 +208,76 @@ public class HiddenSequencesTest } /** + * Test the method that finds the visible row position a given distance before + * another row + */ + @Test(groups = { "Functional" }) + public void testFindIndexNFromRow() + { + AlignmentI al = new Alignment(seqs); + HiddenSequences hs = new HiddenSequences(al); + + // test that without hidden rows, findIndexNFromRow returns + // position n above provided position + int pos = hs.subtractVisibleRows(3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = hs.subtractVisibleRows(0, 10); + assertEquals(10, pos); + + // overflow to top returns negative number + pos = hs.subtractVisibleRows(3, 0); + assertEquals(-3, pos); + + // test that with hidden rows above result row + // behaviour is the same as above + hs.hideSequence(seqs[1]); + hs.hideSequence(seqs[2]); + hs.hideSequence(seqs[3]); + + // position n above provided position + pos = hs.subtractVisibleRows(3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = hs.subtractVisibleRows(0, 10); + assertEquals(10, pos); + + // test with one set of hidden rows between start and required position + hs.hideSequence(seqs[12]); + hs.hideSequence(seqs[13]); + hs.hideSequence(seqs[14]); + hs.hideSequence(seqs[15]); + pos = hs.subtractVisibleRows(8, 17); + assertEquals(5, pos); + + // test with two sets of hidden rows between start and required position + hs.hideSequence(seqs[20]); + hs.hideSequence(seqs[21]); + pos = hs.subtractVisibleRows(8, 23); + assertEquals(9, pos); + + // repeat last 2 tests with no hidden columns to left of required position + hs.showAll(null); + + // test with one set of hidden rows between start and required position + hs.hideSequence(seqs[12]); + hs.hideSequence(seqs[13]); + hs.hideSequence(seqs[14]); + hs.hideSequence(seqs[15]); + pos = hs.subtractVisibleRows(8, 17); + assertEquals(5, pos); + + // test with two sets of hidden rows between start and required position + hs.hideSequence(seqs[20]); + hs.hideSequence(seqs[21]); + pos = hs.subtractVisibleRows(8, 23); + assertEquals(9, pos); + + } + + /** * Test the method that reconstructs (sort of) the full alignment including * hidden sequences */ @@ -289,7 +360,7 @@ public class HiddenSequencesTest assertTrue(al.getSequences().contains(seqs[1])); HiddenSequences hs = al.getHiddenSequences(); assertEquals(0, hs.getSize()); - assertEquals(10, al.getHeight()); + assertEquals(SEQ_COUNT, al.getHeight()); /* * hide the second sequence in the alignment @@ -299,7 +370,7 @@ public class HiddenSequencesTest assertTrue(hs.isHidden(seqs[1])); assertFalse(al.getSequences().contains(seqs[1])); assertEquals(1, hs.getSize()); - assertEquals(9, al.getHeight()); + assertEquals(SEQ_COUNT - 1, al.getHeight()); assertSame(seqs[2], al.getSequenceAt(1)); /* @@ -312,7 +383,7 @@ public class HiddenSequencesTest assertFalse(al.getSequences().contains(seqs[1])); assertFalse(al.getSequences().contains(seqs[2])); assertEquals(2, hs.getSize()); - assertEquals(8, al.getHeight()); + assertEquals(SEQ_COUNT - 2, al.getHeight()); /* * perform 'reveal' on what is now the second sequence in the alignment @@ -323,7 +394,54 @@ public class HiddenSequencesTest assertTrue(revealed.contains(seqs[1])); assertTrue(revealed.contains(seqs[2])); assertEquals(0, hs.getSize()); - assertEquals(10, al.getHeight()); + assertEquals(SEQ_COUNT, al.getHeight()); + } + + /** + * Test the method that adds a sequence to the hidden sequences and deletes it + * from the alignment, and its converse, where the first hidden sequences are + * at the bottom of the alignment (JAL-2437) + */ + @Test(groups = "Functional") + public void testHideShowLastSequences() + { + AlignmentI al = new Alignment(seqs); + assertTrue(al.getSequences().contains(seqs[1])); + HiddenSequences hs = al.getHiddenSequences(); + assertEquals(0, hs.getSize()); + assertEquals(SEQ_COUNT, al.getHeight()); + + /* + * hide the last sequence in the alignment + */ + hs.hideSequence(seqs[SEQ_COUNT - 1]); + assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2])); + assertTrue(hs.isHidden(seqs[SEQ_COUNT - 1])); + assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 1])); + assertEquals(1, hs.getSize()); + assertEquals(SEQ_COUNT - 1, al.getHeight()); + + /* + * hide the third last sequence in the alignment + */ + hs.hideSequence(seqs[SEQ_COUNT - 3]); + assertFalse(hs.isHidden(seqs[SEQ_COUNT - 2])); + assertTrue(hs.isHidden(seqs[SEQ_COUNT - 3])); + assertFalse(al.getSequences().contains(seqs[SEQ_COUNT - 3])); + assertEquals(2, hs.getSize()); + assertEquals(SEQ_COUNT - 2, al.getHeight()); + + /* + * reveal all the sequences, which should be reinstated in the same order as they started in + */ + hs.showAll(null); + assertFalse(hs.isHidden(seqs[SEQ_COUNT - 3])); + assertFalse(hs.isHidden(seqs[SEQ_COUNT - 1])); + assertEquals(seqs[SEQ_COUNT - 3], al.getSequences().get(SEQ_COUNT - 3)); + assertEquals(seqs[SEQ_COUNT - 2], al.getSequences().get(SEQ_COUNT - 2)); + assertEquals(seqs[SEQ_COUNT - 1], al.getSequences().get(SEQ_COUNT - 1)); + assertEquals(0, hs.getSize()); + assertEquals(SEQ_COUNT, al.getHeight()); } @Test(groups = "Functional") diff --git a/test/jalview/gui/AlignmentPanelTest.java b/test/jalview/gui/AlignmentPanelTest.java new file mode 100644 index 0000000..c580a88 --- /dev/null +++ b/test/jalview/gui/AlignmentPanelTest.java @@ -0,0 +1,220 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.gui; + +import static org.testng.Assert.assertEquals; + +import jalview.bin.Cache; +import jalview.bin.Jalview; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.FileLoader; +import jalview.viewmodel.ViewportRanges; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class AlignmentPanelTest +{ + SequenceI seq1 = new Sequence( + "Seq1", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq2 = new Sequence( + "Seq2", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq3 = new Sequence( + "Seq3", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq4 = new Sequence( + "Seq4", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq5 = new Sequence( + "Seq5", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq6 = new Sequence( + "Seq6", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq7 = new Sequence( + "Seq7", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq8 = new Sequence( + "Seq8", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq9 = new Sequence( + "Seq9", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq10 = new Sequence( + "Seq10", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq11 = new Sequence( + "Seq11", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq12 = new Sequence( + "Seq12", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq13 = new Sequence( + "Seq13", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq14 = new Sequence( + "Seq14", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq15 = new Sequence( + "Seq15", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq16 = new Sequence( + "Seq16", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq17 = new Sequence( + "Seq17", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq18 = new Sequence( + "Seq18", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq19 = new Sequence( + "Seq19", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq20 = new Sequence( + "Seq20", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq21 = new Sequence( + "Seq21", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq22 = new Sequence( + "Seq22", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + SequenceI seq23 = new Sequence( + "Seq23", + "ABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBACABCABCABCABCABCABCABCABCBACBACBACBAC"); + + AlignFrame af; + + @BeforeMethod(alwaysRun = true) + public void setUp() + { + Jalview.main(new String[] { "-nonews", "-props", + "test/jalview/testProps.jvprops" }); + + Cache.applicationProperties.setProperty("SHOW_IDENTITY", + Boolean.TRUE.toString()); + af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa", + DataSourceType.FILE); + + /* + * wait for Consensus thread to complete + */ + synchronized (this) + { + while (af.getViewport().getConsensusSeq() == null) + { + try + { + wait(50); + } catch (InterruptedException e) + { + } + } + } + } + + + /** + * Test side effect that end residue is set correctly by setScrollValues, with + * or without hidden columns + */ + @Test(groups = "Functional") + public void TestSetScrollValues() + { + ViewportRanges ranges = af.getViewport().getRanges(); + + int oldres = ranges.getEndRes(); + af.alignPanel.setScrollValues(-1, 5); + + // setting -ve x value does not change residue + assertEquals(ranges.getEndRes(), oldres); + + af.alignPanel.setScrollValues(0, 5); + + // setting 0 as x value does not change residue + assertEquals(ranges.getEndRes(), oldres); + + af.alignPanel.setScrollValues(5, 5); + // setting x value to 5 extends endRes by 5 residues + assertEquals(ranges.getEndRes(), oldres + 5); + + // scroll to position after hidden columns sets endres to oldres (width) + + // position + int scrollpos = 60; + af.getViewport().hideColumns(30, 50); + af.alignPanel.setScrollValues(scrollpos, 5); + assertEquals(ranges.getEndRes(), oldres + scrollpos); + + // scroll to position within hidden columns, still sets endres to oldres + + // position + // not sure if this is actually correct behaviour but this is what Jalview + // currently does + scrollpos = 40; + af.getViewport().showAllHiddenColumns(); + af.getViewport().hideColumns(30, 50); + af.alignPanel.setScrollValues(scrollpos, 5); + assertEquals(ranges.getEndRes(), oldres + scrollpos); + + // scroll to position within distance of the end of the alignment + // endRes should be set to width of alignment - 1 + scrollpos = 130; + af.getViewport().showAllHiddenColumns(); + af.alignPanel.setScrollValues(scrollpos, 5); + assertEquals(ranges.getEndRes(), af.getViewport() + .getAlignment().getWidth() - 1); + + // now hide some columns, and scroll to position within + // distance of the end of the alignment + // endRes should be set to width of alignment - 1 - the number of hidden + // columns + af.getViewport().hideColumns(30, 50); + af.alignPanel.setScrollValues(scrollpos, 5); + assertEquals(ranges.getEndRes(), af.getViewport() + .getAlignment().getWidth() - 1 - 21); // 21 is the number of hidden + // columns + } +} diff --git a/test/jalview/viewmodel/OverviewDimensionsTest.java b/test/jalview/viewmodel/OverviewDimensionsTest.java new file mode 100644 index 0000000..398fec3 --- /dev/null +++ b/test/jalview/viewmodel/OverviewDimensionsTest.java @@ -0,0 +1,1037 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.viewmodel; + +import static org.testng.Assert.assertEquals; + +import jalview.analysis.AlignmentGenerator; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.ColumnSelection; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceCollectionI; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; + +import java.util.Hashtable; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +@Test(singleThreaded = true) +public class OverviewDimensionsTest +{ + AlignmentI al; + OverviewDimensions od; + + // cached widths and heights + int boxWidth; + int boxHeight; + int viewHeight; + int viewWidth; + int alheight; + int alwidth; + + ViewportRanges vpranges; + + Hashtable hiddenRepSequences = new Hashtable(); + + ColumnSelection hiddenCols = new ColumnSelection(); + + @BeforeClass(alwaysRun = true) + public void setUpJvOptionPane() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + al = gen.generate(157, 525, 123, 5, 5); + } + + @BeforeMethod(alwaysRun = true) + public void setUp() + { + if (!hiddenRepSequences.isEmpty()) + { + al.getHiddenSequences().showAll(hiddenRepSequences); + } + hiddenCols.revealAllHiddenColumns(); + + vpranges = new ViewportRanges(al); + vpranges.setStartRes(0); + vpranges.setEndRes(62); + vpranges.setStartSeq(0); + vpranges.setEndSeq(17); + + viewHeight = vpranges.getEndSeq() - vpranges.getStartSeq() + 1; + viewWidth = vpranges.getEndRes() - vpranges.getStartRes() + 1; + + ColumnSelection hiddenCols = new ColumnSelection(); + + od = new OverviewDimensions(vpranges, true); + // Initial box sizing - default path through code + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + + mouseClick(od, 0, 0); + moveViewport(0, 0); + + // calculate before hidden columns so we get absolute values + alheight = vpranges.getAbsoluteAlignmentHeight(); + alwidth = vpranges.getAbsoluteAlignmentWidth(); + + boxWidth = Math.round((float) (vpranges.getEndRes() + - vpranges.getStartRes() + 1) + * od.getWidth() / alwidth); + boxHeight = Math.round((float) (vpranges.getEndSeq() + - vpranges.getStartSeq() + 1) + * od.getSequencesHeight() / alheight); + } + + @AfterClass(alwaysRun = true) + public void cleanUp() + { + al = null; + } + + /** + * Test that the OverviewDimensions constructor sets width and height + * correctly + */ + @Test(groups = { "Functional" }) + public void testConstructor() + { + SequenceI seqa = new Sequence("Seq1", "ABC"); + SequenceI seqb = new Sequence("Seq2", "ABC"); + SequenceI seqc = new Sequence("Seq3", "ABC"); + SequenceI seqd = new Sequence("Seq4", "ABC"); + SequenceI seqe = new Sequence("Seq5", + "ABCABCABCABCABCABCABCABCBACBACBACBAC"); + + int defaultGraphHeight = 20; + int maxWidth = 400; + int minWidth = 120; + int maxSeqHeight = 300; + int minSeqHeight = 40; + + // test for alignment with width > height + SequenceI[] seqs1 = new SequenceI[] { seqa, seqb }; + Alignment al1 = new Alignment(seqs1); + ViewportRanges props = new ViewportRanges(al1); + + OverviewDimensions od = new OverviewDimensions(props, true); + int scaledHeight = 267; + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), scaledHeight); + assertEquals(od.getWidth(), maxWidth); + assertEquals(od.getHeight(), scaledHeight + defaultGraphHeight); + + // test for alignment with width < height + SequenceI[] seqs2 = new SequenceI[] { seqa, seqb, seqc, seqd }; + Alignment al2 = new Alignment(seqs2); + props = new ViewportRanges(al2); + + od = new OverviewDimensions(props, true); + int scaledWidth = 300; + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), maxSeqHeight); + assertEquals(od.getWidth(), scaledWidth); + assertEquals(od.getHeight(), scaledWidth + defaultGraphHeight); + + // test for alignment with width > height and sequence height scaled below + // min value + SequenceI[] seqs3 = new SequenceI[] { seqe }; + Alignment al3 = new Alignment(seqs3); + props = new ViewportRanges(al3); + + od = new OverviewDimensions(props, true); + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), minSeqHeight); + assertEquals(od.getWidth(), maxWidth); + assertEquals(od.getHeight(), minSeqHeight + defaultGraphHeight); + + // test for alignment with width < height and width scaled below min value + SequenceI[] seqs4 = new SequenceI[] { seqa, seqb, seqc, seqd, seqa, + seqb, seqc, seqd, seqa, seqb, seqc, seqd, seqa, seqb, seqc, seqd }; + Alignment al4 = new Alignment(seqs4); + props = new ViewportRanges(al4); + + od = new OverviewDimensions(props, true); + assertEquals(od.getGraphHeight(), defaultGraphHeight); + assertEquals(od.getSequencesHeight(), maxSeqHeight); + assertEquals(od.getWidth(), minWidth); + assertEquals(od.getHeight(), maxSeqHeight + defaultGraphHeight); + + Alignment al5 = new Alignment(seqs4); + props = new ViewportRanges(al5); + + od = new OverviewDimensions(props, false); + assertEquals(od.getGraphHeight(), 0); + assertEquals(od.getSequencesHeight(), maxSeqHeight); + assertEquals(od.getWidth(), minWidth); + assertEquals(od.getHeight(), maxSeqHeight); + } + + /** + * Test that validation after mouse adjustments to boxX and boxY sets box + * dimensions and scroll values correctly, when there are no hidden rows or + * columns. + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromMouseClick() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // negative boxX value reset to 0 + mouseClick(od, -5, 10); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollRow(), + Math.round((float) 10 * alheight / od.getSequencesHeight())); + assertEquals(od.getScrollCol(), 0); + + // negative boxY value reset to 0 + mouseClick(od, 6, -2); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) 6 * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // overly large boxX value reset to width-boxWidth + mouseClick(od, 100, 6); + assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()); + assertEquals(od.getBoxY(), 6); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + // overly large boxY value reset to sequenceHeight - boxHeight + mouseClick(od, 10, 520); + assertEquals(od.getBoxX(), 10); + assertEquals(od.getBoxY(), od.getSequencesHeight() - od.getBoxHeight()); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + + // here (float) od.getBoxY() * alheight / od.getSequencesHeight() = 507.5 + // and round rounds to 508; however we get 507 working with row values + // hence the subtraction of 1 + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight()) - 1); + + // click past end of alignment, as above + mouseClick(od, 3000, 5); + assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + // move viewport so startRes non-zero and then mouseclick + moveViewportH(50); + + // click at viewport position + int oldboxx = od.getBoxX(); + int oldboxy = od.getBoxY(); + mouseClick(od, od.getBoxX() + 5, od.getBoxY() + 2); + assertEquals(od.getBoxX(), oldboxx + 5); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getBoxY(), oldboxy + 2); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + // click at top corner + mouseClick(od, 0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test setting of the box position, when there are hidden cols at the start + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenColsAtStart() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide cols at start and check updated box position is correct + // changes boxX but not boxwidth + int lastHiddenCol = 30; + hiddenCols.hideColumns(0, lastHiddenCol); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + assertEquals(od.getBoxX(), + Math.round((float) (lastHiddenCol + 1) * od.getWidth() + / alwidth)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // try to click in hidden cols, check box does not move + int xpos = 10; + mouseClick(od, xpos, 0); + assertEquals( + od.getBoxX(), + Math.round((float) (lastHiddenCol + 1) * od.getWidth() + / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), 0); + + // click to right of hidden columns, box moves to click point + testBoxIsAtClickPoint(40, 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), + Math.round((float) 40 * alwidth / od.getWidth()) + - (lastHiddenCol + 1)); + + // click to right of hidden columns such that box runs over right hand side + // of alignment + // box position is adjusted away from the edge + // overly large boxX value reset to width-boxWidth + xpos = 100; + mouseClick(od, xpos, 5); + assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()); + assertEquals(od.getBoxY(), 5); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth()) + - (lastHiddenCol + 1)); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + } + + /** + * Test setting of the box position, when there are hidden cols in the middle + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenColsInMiddle() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide columns 63-73, no change to box position or dimensions + int firstHidden = 63; + int lastHidden = 73; + hiddenCols.hideColumns(firstHidden, lastHidden); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // move box so that it overlaps with hidden cols on one side + // box width changes, boxX and scrollCol as for unhidden case + int xpos = 55 - boxWidth; // 55 is position in overview approx halfway + // between cols 60 and 70 + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), xpos); + assertEquals(od.getBoxY(), 0); + assertEquals( + od.getBoxWidth(), + Math.round(boxWidth + (float) (lastHidden - firstHidden + 1) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round(xpos * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // move box so that it completely covers hidden cols + // box width changes, boxX and scrollCol as for hidden case + xpos = 33; + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), xpos); + assertEquals(od.getBoxY(), 0); + assertEquals( + od.getBoxWidth(), + Math.round(boxWidth + (float) (lastHidden - firstHidden + 1) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) xpos * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // move box so boxX is in hidden cols, box overhangs at right + // boxX and scrollCol at left of hidden area, box width extends across + // hidden region + xpos = 50; + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), + Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals( + od.getBoxWidth(), + boxWidth + + Math.round((float) (lastHidden - firstHidden + 1) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), firstHidden - 1); + assertEquals(od.getScrollRow(), 0); + + // move box so boxX is to right of hidden cols, but does not go beyond full + // width of alignment + // box width, boxX and scrollCol all as for non-hidden case + xpos = 75; + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), + Math.round(xpos * alwidth / od.getWidth()) + - (lastHidden - firstHidden + 1)); + + // move box so it goes beyond full width of alignment + // boxX, scrollCol adjusted back, box width normal + xpos = 3000; + mouseClick(od, xpos, 5); + assertEquals(od.getBoxX(), od.getWidth() - od.getBoxWidth()); + assertEquals(od.getBoxY(), 5); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round(((float) od.getBoxX() * alwidth / od.getWidth()) + - (lastHidden - firstHidden + 1))); + assertEquals(od.getScrollRow(), + Math.round((float) od.getBoxY() * alheight + / od.getSequencesHeight())); + + } + + /** + * Test setting of the box position, when there are hidden cols at the end of + * the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenColsAtEnd() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide columns 140-164, no change to box position or dimensions + int firstHidden = 140; + int lastHidden = 164; + hiddenCols.hideColumns(firstHidden, lastHidden); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // click to left of hidden cols, without overlapping + // boxX, scrollCol and width as normal + int xpos = 5; + testBoxIsAtClickPoint(xpos, 0); + assertEquals(od.getScrollRow(), 0); + assertEquals(od.getScrollCol(), + Math.round((float) xpos * alwidth / od.getWidth())); + + // click to left of hidden cols, with overlap + // boxX and scrollCol adjusted for hidden cols, width normal + xpos = Math.round((float) 145 * od.getWidth() / alwidth) - boxWidth; + mouseClick(od, xpos, 0); + assertEquals(od.getBoxX(), + Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth) + - boxWidth + 1); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // click in hidden cols + // boxX and scrollCol adjusted for hidden cols, width normal + xpos = 115; + assertEquals(od.getBoxX(), + Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth) + - boxWidth + 1); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + + // click off end of alignment + // boxX and scrollCol adjusted for hidden cols, width normal + xpos = 3000; + assertEquals(od.getBoxX(), + Math.round((float) (firstHidden - 1) * od.getWidth() / alwidth) + - boxWidth + 1); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), + Math.round((float) od.getBoxX() * alwidth / od.getWidth())); + assertEquals(od.getScrollRow(), 0); + } + + /** + * Test that the box position is set correctly when set from the viewport, + * with no hidden rows or columns + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewport() + { + // move viewport to start of alignment + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to right + moveViewportH(70); + assertEquals(od.getBoxX(), + Math.round((float) 70 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport down + moveViewportV(100); + assertEquals(od.getBoxX(), + Math.round((float) 70 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), + Math.round(100 * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to bottom right + moveViewport(98, 508); + assertEquals(od.getBoxX(), + Math.round((float) 98 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), + Math.round((float) 508 * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden columns + * at the start + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenColsAtStart() + { + int firstHidden = 0; + int lastHidden = 20; + hiddenCols.hideColumns(firstHidden, lastHidden); + + // move viewport to start of alignment + moveViewport(0, 0); + assertEquals(od.getBoxX(), + Math.round((float) (lastHidden + 1) * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to end of alignment - need to make startRes by removing + // hidden cols because of how viewport/overview are implemented + moveViewport(98 - lastHidden - 1, 0); + assertEquals(od.getBoxX(), + Math.round((float) 98 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden columns + * in the middle + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenColsInMiddle() + { + int firstHidden = 68; + int lastHidden = 78; + hiddenCols.hideColumns(firstHidden, lastHidden); + + // move viewport before hidden columns + moveViewport(3, 0); + + assertEquals(od.getBoxX(), + Math.round((float) 3 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + System.out.println(od.getBoxWidth()); + assertEquals(od.getBoxWidth(), boxWidth); + System.out.println(od.getBoxWidth()); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to left of hidden columns with overlap + moveViewport(10, 0); + assertEquals(od.getBoxX(), + Math.round((float) 10 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals( + od.getBoxWidth(), + boxWidth + + Math.round((float) (lastHidden - firstHidden + 1) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to straddle hidden columns + moveViewport(63, 0); + assertEquals(od.getBoxX(), + Math.round((float) 63 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals( + od.getBoxWidth(), + boxWidth + + Math.round((lastHidden - firstHidden + 1) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to right of hidden columns, no overlap + moveViewport(80 - (lastHidden - firstHidden + 1), 0); + assertEquals(od.getBoxX(), + Math.round((float) 80 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + } + + /** + * Test that the box position is set correctly when there are hidden columns + * at the end + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenColsAtEnd() + { + int firstHidden = 152; + int lastHidden = 164; + hiddenCols.hideColumns(firstHidden, lastHidden); + + // move viewport before hidden columns + moveViewport(3, 0); + assertEquals(od.getBoxX(), + Math.round((float) 3 * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to hidden columns + // viewport can't actually extend into hidden cols, + // so move to the far right edge of the viewport + moveViewport(firstHidden - viewWidth, 0); + assertEquals(od.getBoxX(), + Math.round((float) (firstHidden - viewWidth) + * od.getWidth() / alwidth)); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden rows at + * the start + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenRowsAtStart() + { + int firstHidden = 0; + int lastHidden = 20; + hideSequences(firstHidden, lastHidden); + + // move viewport to start of alignment: + // box moves to below hidden rows, height remains same + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) (lastHidden + 1) * od.getSequencesHeight() + / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to end of alignment + moveViewport(0, 525 - viewHeight - lastHidden - 1); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) (525 - viewHeight) * od.getSequencesHeight() + / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test that the box position is set correctly when there are hidden rows in + * the middle + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenRowsInMiddle() + { + int firstHidden = 200; + int lastHidden = 210; + hideSequences(firstHidden, lastHidden); + + // move viewport to start of alignment: + // box, height etc as in non-hidden case + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to straddle hidden rows + moveViewport(0, 198); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), Math.round ((float)198 * od.getSequencesHeight() + / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals( + od.getBoxHeight(), + Math.round((float) (viewHeight + lastHidden - firstHidden + 1) + * od.getSequencesHeight() / alheight)); + } + + /** + * Test that the box position is set correctly when there are hidden rows at + * the bottom + */ + @Test(groups = { "Functional" }) + public void testSetBoxFromViewportHiddenRowsAtEnd() + { + int firstHidden = 500; + int lastHidden = 524; + hideSequences(firstHidden, lastHidden); + + // move viewport to start of alignment: + // box, height etc as in non-hidden case + moveViewport(0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // move viewport to end of alignment + // viewport sits above hidden rows and does not include them + moveViewport(0, firstHidden - viewHeight - 1); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) (firstHidden - viewHeight - 1) + * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + } + + /** + * Test setting of the box position, when there are hidden rows at the start + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenRowsAtStart() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide rows at start and check updated box position is correct + // changes boxY but not boxheight + int lastHiddenRow = 30; + hideSequences(0, lastHiddenRow); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) (lastHiddenRow + 1) + * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click in hidden rows - same result + mouseClick(od, 0, 0); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) (lastHiddenRow + 1) + * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click below hidden rows + mouseClick(od, 0, 150); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 150); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /** + * Test setting of the box position, when there are hidden rows at the middle + * of the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenRowsInMiddle() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide rows in middle and check updated box position is correct + // no changes + int firstHiddenRow = 50; + int lastHiddenRow = 54; + hideSequences(firstHiddenRow, lastHiddenRow); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click above hidden rows, so that box overlaps + int ypos = 35; // column value in residues + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals( + od.getBoxHeight(), + boxHeight + + Math.round((float) (lastHiddenRow - firstHiddenRow + 1) + * od.getSequencesHeight() / alheight)); + + // click so that box straddles hidden rows + ypos = 44; // column value in residues + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals( + od.getBoxHeight(), + boxHeight + + Math.round((float) (lastHiddenRow - firstHiddenRow + 1) + * od.getSequencesHeight() / alheight)); + } + + /** + * Test setting of the box position, when there are hidden rows at the end of + * the alignment + */ + @Test(groups = { "Functional" }) + public void testFromMouseWithHiddenRowsAtEnd() + { + od.updateViewportFromMouse(0, 0, al.getHiddenSequences(), hiddenCols, + vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + assertEquals(od.getScrollCol(), 0); + assertEquals(od.getScrollRow(), 0); + + // hide rows at end and check updated box position is correct + // no changes + int firstHidden = 500; + int lastHidden = 524; + hideSequences(firstHidden, lastHidden); + + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), 0); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click above hidden rows + int ypos = 40; // row 40 + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals(od.getBoxY(), + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click above hidden rows so box overlaps + // boxY moved upwards, boxHeight remains same + ypos = 497; // row 497 + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((float) (firstHidden - viewHeight) + * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + // click within hidden rows + ypos = 505; + mouseClick(od, 0, + Math.round((float) ypos * od.getSequencesHeight() / alheight)); + assertEquals(od.getBoxX(), 0); + assertEquals( + od.getBoxY(), + Math.round((firstHidden - viewHeight) * od.getSequencesHeight() + / alheight)); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + } + + /* + * Move viewport horizontally: startRes + previous width gives new horizontal extent. Vertical extent stays the same. + */ + private void moveViewportH(int startRes) + { + vpranges.setStartRes(startRes); + vpranges.setEndRes(startRes + viewWidth - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + } + + /* + * Move viewport vertically: startSeq and endSeq give new vertical extent. Horizontal extent stays the same. + */ + private void moveViewportV(int startSeq) + { + vpranges.setStartSeq(startSeq); + vpranges.setEndSeq(startSeq + viewHeight - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + } + + /* + * Move viewport horizontally and vertically. + */ + private void moveViewport(int startRes, int startSeq) + { + vpranges.setStartRes(startRes); + vpranges.setEndRes(startRes + viewWidth - 1); + vpranges.setStartSeq(startSeq); + vpranges.setEndSeq(startSeq + viewHeight - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + } + + /* + * Mouse click as position x,y in overview window + */ + private void mouseClick(OverviewDimensions od, int x, int y) + { + od.updateViewportFromMouse(x, y, al.getHiddenSequences(), hiddenCols, + vpranges); + + // updates require an OverviewPanel to exist which it doesn't here + // so call setBoxPosition() as it would be called by the AlignmentPanel + // normally + + vpranges.setStartRes(od.getScrollCol()); + vpranges.setEndRes(od.getScrollCol() + viewWidth - 1); + vpranges.setStartSeq(od.getScrollRow()); + vpranges.setEndSeq(od.getScrollRow() + viewHeight - 1); + od.setBoxPosition(al.getHiddenSequences(), hiddenCols, vpranges); + } + + /* + * Test that the box is positioned with the top left corner at xpos, ypos + * and with the original width and height + */ + private void testBoxIsAtClickPoint(int xpos, int ypos) + { + mouseClick(od, xpos, ypos); + assertEquals(od.getBoxX(), xpos); + assertEquals(od.getBoxY(), ypos); + assertEquals(od.getBoxWidth(), boxWidth); + assertEquals(od.getBoxHeight(), boxHeight); + + } + + /* + * Hide sequences between start and end + */ + private void hideSequences(int start, int end) + { + SequenceI[] allseqs = al.getSequencesArray(); + SequenceGroup theseSeqs = new SequenceGroup(); + + for (int i = start; i <= end; i++) + { + theseSeqs.addSequence(allseqs[i], false); + al.getHiddenSequences().hideSequence(allseqs[i]); + } + + hiddenRepSequences.put(allseqs[start], theseSeqs); + } +} diff --git a/test/jalview/viewmodel/ViewportRangesTest.java b/test/jalview/viewmodel/ViewportRangesTest.java new file mode 100644 index 0000000..cfd03cd --- /dev/null +++ b/test/jalview/viewmodel/ViewportRangesTest.java @@ -0,0 +1,100 @@ +package jalview.viewmodel; + +import static org.testng.Assert.assertEquals; + +import jalview.analysis.AlignmentGenerator; +import jalview.datamodel.AlignmentI; + +import org.testng.annotations.Test; + +public class ViewportRangesTest { + + AlignmentGenerator gen = new AlignmentGenerator(false); + + AlignmentI al = gen.generate(20, 30, 1, 5, 5); + + @Test + public void testViewportRanges() + { + ViewportRanges vr = new ViewportRanges(al); + + assertEquals(vr.getStartRes(),0); + assertEquals(vr.getEndRes(), al.getWidth()-1); + assertEquals(vr.getStartSeq(), 0); + assertEquals(vr.getEndSeq(), al.getHeight() - 1); + } + + @Test + public void testGetAbsoluteAlignmentHeight() + { + ViewportRanges vr = new ViewportRanges(al); + + assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight()); + + al.getHiddenSequences().hideSequence(al.getSequenceAt(3)); + assertEquals(vr.getAbsoluteAlignmentHeight(), al.getHeight() + 1); + } + + @Test + public void testGetAbsoluteAlignmentWidth() + { + ViewportRanges vr = new ViewportRanges(al); + assertEquals(vr.getAbsoluteAlignmentWidth(), al.getWidth()); + } + + @Test + public void testSetEndRes() + { + ViewportRanges vr = new ViewportRanges(al); + vr.setEndRes(-1); + assertEquals(vr.getEndRes(), 0); + + vr.setEndRes(al.getWidth()); + assertEquals(vr.getEndRes(), al.getWidth() - 1); + + vr.setEndRes(al.getWidth() - 1); + assertEquals(vr.getEndRes(), al.getWidth() - 1); + } + + @Test + public void testSetEndSeq() + { + ViewportRanges vr = new ViewportRanges(al); + vr.setEndSeq(-1); + assertEquals(vr.getEndSeq(), 0); + + vr.setEndSeq(al.getHeight()); + assertEquals(vr.getEndSeq(), al.getHeight() - 1); + + vr.setEndRes(al.getHeight() - 1); + assertEquals(vr.getEndSeq(), al.getHeight() - 1); + } + + @Test + public void testSetStartRes() + { + ViewportRanges vr = new ViewportRanges(al); + vr.setStartRes(-1); + assertEquals(vr.getStartRes(), 0); + + vr.setStartRes(al.getWidth()); + assertEquals(vr.getStartRes(), al.getWidth() - 1); + + vr.setStartRes(al.getWidth() - 1); + assertEquals(vr.getStartRes(), al.getWidth() - 1); + } + + @Test + public void testSetStartSeq() + { + ViewportRanges vr = new ViewportRanges(al); + vr.setStartSeq(-1); + assertEquals(vr.getStartSeq(), 0); + + vr.setStartSeq(al.getHeight()); + assertEquals(vr.getStartSeq(), al.getHeight() - 1); + + vr.setStartSeq(al.getHeight() - 1); + assertEquals(vr.getStartSeq(), al.getHeight() - 1); + } +} diff --git a/test/jalview/ws/jabaws/JpredJabaStructExportImport.java b/test/jalview/ws/jabaws/JpredJabaStructExportImport.java index a21cfeb..d5b6ed1 100644 --- a/test/jalview/ws/jabaws/JpredJabaStructExportImport.java +++ b/test/jalview/ws/jabaws/JpredJabaStructExportImport.java @@ -25,41 +25,34 @@ import static org.testng.AssertJUnit.assertTrue; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; -import jalview.gui.AlignFrame; import jalview.gui.Jalview2XML; import jalview.gui.JvOptionPane; import jalview.io.AnnotationFile; import jalview.io.DataSourceType; import jalview.io.FileFormat; -import jalview.io.FileLoader; import jalview.io.FormatAdapter; import jalview.io.StockholmFileTest; import jalview.ws.jws2.JPred301Client; import jalview.ws.jws2.JabaParamStore; +import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.jws2.SequenceAnnotationWSClient; import jalview.ws.jws2.jabaws2.Jws2Instance; import jalview.ws.params.AutoCalcSetting; import java.awt.Component; -import java.net.ConnectException; import java.util.ArrayList; import java.util.List; import javax.swing.JMenu; import javax.swing.JMenuItem; -import javax.xml.ws.WebServiceException; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import compbio.data.msa.Category; -import compbio.data.msa.JABAService; import compbio.metadata.Argument; import compbio.metadata.WrongParameterException; -import compbio.ws.client.Jws2Client; -import compbio.ws.client.Services; public class JpredJabaStructExportImport { @@ -71,56 +64,36 @@ public class JpredJabaStructExportImport JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } - private static String testseqs = "examples/uniref50.fa"; + public static String testseqs = "examples/uniref50.fa"; - private static Jws2Instance jpredws; + public static Jws2Discoverer disc; - private static AlignFrame af = null; + public static Jws2Instance jpredws; + + jalview.ws.jws2.JPred301Client jpredClient; + + public static jalview.gui.AlignFrame af = null; @BeforeClass(alwaysRun = true) - public static void setUpBeforeClass() throws ConnectException, - WebServiceException + public static void setUpBeforeClass() throws Exception { Cache.loadProperties("test/jalview/io/testProps.jvprops"); - Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", - Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("SHOW_QUALITY", - Boolean.FALSE.toString()); - Cache.applicationProperties.setProperty("SHOW_CONSERVATION", - Boolean.FALSE.toString()); - Cache.applicationProperties.setProperty("SHOW_IDENTITY", - Boolean.FALSE.toString()); Cache.initLogger(); - getJabaws(); + disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false); - FileLoader fl = new FileLoader(false); - af = fl.LoadFileWaitTillLoaded(testseqs, DataSourceType.FILE); - assertNotNull("Couldn't load test data ('" + testseqs + "')", af); - } - - /** - * @throws WebServiceException - * @throws ConnectException - * - */ - static void getJabaws() throws ConnectException, WebServiceException - { - String jabaws = "http://www.compbio.dundee.ac.uk/jabaws"; - JABAService service = null; - for (Category category : Category.getCategories()) + for (Jws2Instance svc : disc.getServices()) { - for (Services srv : category.getServices()) + if (svc.getServiceTypeURI().toLowerCase().contains("jpred")) { - if ("JpredWS".equals(srv.name())) - { - service = Jws2Client.connect(jabaws, srv); - } + jpredws = svc; } } - jpredws = new Jws2Instance(jabaws, "JpredWs", - "Secondary Structure Prediction", - "SERVICE: JpredWS version 3.0.3", service); + + System.out.println("State of jpredws: " + jpredws); Assert.assertNotNull(jpredws, "jpredws is null!"); + jalview.io.FileLoader fl = new jalview.io.FileLoader(false); + af = fl.LoadFileWaitTillLoaded(testseqs, jalview.io.DataSourceType.FILE); + assertNotNull("Couldn't load test data ('" + testseqs + "')", af); } @AfterClass(alwaysRun = true) @@ -133,7 +106,7 @@ public class JpredJabaStructExportImport } } - @Test(groups = { "Network" }) + @Test(groups = { "Functional" }) public void testJPredStructOneSeqOnly() { af.selectAllSequenceMenuItem_actionPerformed(null); @@ -143,7 +116,7 @@ public class JpredJabaStructExportImport af.getViewport().getSelectionGroup().getSequenceAt(0), false); af.hideSelSequences_actionPerformed(null); - JPred301Client jpredClient = new JPred301Client(jpredws, af, null, null); + jpredClient = new JPred301Client(jpredws, af, null, null); assertTrue( "Didn't find any default args to check for. Buggy implementation of hardwired arguments in client.", @@ -185,16 +158,11 @@ public class JpredJabaStructExportImport } - /* - * test disabled pending completion of JAL-1601 - * (JPred301Client is currently hidden in Jalview in - * - */ - @Test(groups = { "Network" }) - public void testJPredStructExport() throws InterruptedException + @Test(groups = { "Functional" }) + public void testJPredStructExport() { - JPred301Client jpredClient = new JPred301Client(jpredws, af, null, null); + jpredClient = new JPred301Client(jpredws, af, null, null); af.getViewport().getCalcManager().startWorker(jpredClient); @@ -209,24 +177,18 @@ public class JpredJabaStructExportImport ; } while (af.getViewport().getCalcManager().isWorking()); - synchronized (this) - { - wait(2000); - } AlignmentI orig_alig = af.getViewport().getAlignment(); - System.out.println("Alignment now has " - + orig_alig.getAlignmentAnnotation().length + " annotations"); - verifyAnnotationFileIO("Testing JPredWS Annotation IO", orig_alig); + + testAnnotationFileIO("Testing JPredWS Annotation IO", orig_alig); } - protected static void verifyAnnotationFileIO(String testname, - AlignmentI al) + public static void testAnnotationFileIO(String testname, AlignmentI al) { try { // what format would be appropriate for RNAalifold annotations? - String aligfileout = FileFormat.Fasta.getWriter(null).print( + String aligfileout = FileFormat.Pfam.getWriter(null).print( al.getSequencesArray(), true); String anfileout = new AnnotationFile() @@ -261,16 +223,16 @@ public class JpredJabaStructExportImport } catch (Exception e) { e.printStackTrace(); - Assert.fail("Test " - + testname - + "\nCouldn't complete Annotation file roundtrip input/output/input test."); } + Assert.fail("Test " + + testname + + "\nCouldn't complete Annotation file roundtrip input/output/input test."); } - @Test(groups = { "Network" }, enabled = false) + @Test(groups = { "Functional" }) public void testJpredwsSettingsRecovery() { - Assert.fail("not implemented"); + Assert.fail("not implemnented"); List opts = new ArrayList(); for (compbio.metadata.Argument rg : (List) jpredws .getRunnerConfig().getArguments()) @@ -292,7 +254,7 @@ public class JpredJabaStructExportImport opts.add(rg); } } - JPred301Client jpredClient = new JPred301Client(jpredws, af, null, opts); + jpredClient = new JPred301Client(jpredws, af, null, opts); af.getViewport().getCalcManager().startWorker(jpredClient); diff --git a/test/jalview/ws/seqfetcher/DasSequenceFetcher.java b/test/jalview/ws/seqfetcher/DasSequenceFetcher.java index 98ca303..f1dafcb 100644 --- a/test/jalview/ws/seqfetcher/DasSequenceFetcher.java +++ b/test/jalview/ws/seqfetcher/DasSequenceFetcher.java @@ -20,9 +20,11 @@ */ package jalview.ws.seqfetcher; +import static org.testng.Assert.assertTrue; + +import jalview.bin.Cache; import jalview.gui.JvOptionPane; -import org.testng.AssertJUnit; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -36,15 +38,12 @@ public class DasSequenceFetcher JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } - @Test(groups = { "Functional" }) + @Test(groups = { "Network" }) public void testDasRegistryContact() { - jalview.bin.Cache.getDasSourceRegistry().refreshSources(); - AssertJUnit - .assertTrue( - "Expected to find at least one DAS source at the registry. Check config.", - jalview.bin.Cache.getDasSourceRegistry().getSources() - .size() > 0); + Cache.getDasSourceRegistry().refreshSources(); + assertTrue(Cache.getDasSourceRegistry().getSources().isEmpty(), + "Expected to find no DAS sources at the registry. Check config."); } } diff --git a/test/jalview/ws/sifts/SiftsClientTest.java b/test/jalview/ws/sifts/SiftsClientTest.java index d805e47..7f8adc9 100644 --- a/test/jalview/ws/sifts/SiftsClientTest.java +++ b/test/jalview/ws/sifts/SiftsClientTest.java @@ -38,6 +38,8 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; import org.testng.Assert; import org.testng.FileAssert; @@ -280,7 +282,19 @@ public class SiftsClientTest "A", testSeq, null); Assert.assertEquals(testSeq.getStart(), 1); Assert.assertEquals(testSeq.getEnd(), 147); - Assert.assertEquals(actualMapping, expectedMapping); + // Can't do Assert.assertEquals(actualMapping, expectedMapping); + // because this fails in our version of TestNG + Assert.assertEquals(actualMapping.size(), expectedMapping.size()); + Iterator> it = expectedMapping.entrySet() + .iterator(); + while (it.hasNext()) + { + Map.Entry pair = it.next(); + Assert.assertTrue(actualMapping.containsKey(pair.getKey())); + Assert.assertEquals(actualMapping.get(pair.getKey()), + pair.getValue()); + } + } catch (Exception e) { e.printStackTrace(); @@ -399,7 +413,21 @@ groups = { "Network" }, Assert.assertEquals(strucMapping.getMappingDetailsOutput(), expectedMappingOutput); - Assert.assertEquals(strucMapping.getMapping(), expectedMapping); + + // Can't do Assert.assertEquals(strucMapping.getMapping(), expectedMapping); + // because this fails in our version of TestNG + Assert.assertEquals(strucMapping.getMapping().size(), + expectedMapping.size()); + Iterator> it = expectedMapping.entrySet() + .iterator(); + while (it.hasNext()) + { + Map.Entry pair = it.next(); + Assert.assertTrue(strucMapping.getMapping() + .containsKey(pair.getKey())); + Assert.assertEquals(strucMapping.getMapping().get(pair.getKey()), + pair.getValue()); + } } @Test(groups = { "Network" })