/* * 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.api.ViewStyleI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Map; /** * Supplies and updates viewport properties relating to position such as: start * and end residues and sequences, hidden column/row adjustments, ratio of * viewport to alignment etc */ public class ViewportPositionProps 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; // character height private int charHeight; // character width private int charWidth; // alignment private AlignmentI al; // viewstyle private ViewStyleI viewstyle; // hidden column data protected ColumnSelection colSel = new ColumnSelection(); private long colselhash = -1; // hidden sequence data private Map hiddenRepSequences; /** * Constructor * @param alignment TODO */ public ViewportPositionProps(AlignmentI alignment, ViewStyleI vstyle) { // initial values of viewport settings this.startRes = 0; this.endRes = alignment.getWidth() - 1; this.startSeq = 0; this.endSeq = alignment.getHeight() - 1; this.al = alignment; this.viewstyle = vstyle; } public void setCharHeight(int h) { viewstyle.setCharHeight(h); } public void setCharWidth(int w) { viewstyle.setCharWidth(w); } // ways to update values // ways to notify of changes // ways to supply positional information /** * Get alignment width */ public int getAlignmentWidthInCols() { return al.getWidth(); } /** * Get alignment height */ public int getAlignmentHeightInRows() { return al.getHeight(); } public void setStartRes(int res) { if (res > al.getWidth() - 1) { res = al.getWidth() - 1; } else if (res < 0) { res = 0; } this.startRes = res; } public void setEndRes(int res) { if (res > al.getWidth() - 1) { res = al.getWidth() - 1; } else if (res < 0) { res = 0; } this.endRes = res; } public void setStartSeq(int seq) { if (seq > al.getHeight()) { seq = al.getHeight(); } else if (seq < 0) { seq = 0; } this.startSeq = seq; } public void setEndSeq(int seq) { if (seq > al.getHeight()) { seq = al.getHeight(); } 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; } /** * Get start residue of viewport */ public int getStartRes(boolean countHidden) { if (countHidden) { return 0; // av.getColumnSelection().adjustForHiddenColumns(startRes); } else { return startRes; } } /** * Convert distance x in viewport pixels to a distance in number of residues * * @param x * number of pixels * @return number of residues */ public int convertPixelsToResidues(int x) { return Math.round((float) x / viewstyle.getCharWidth()); } /** * Convert distance y in viewport pixels to a distance in number of sequences * * @param y * number of pixels * @return number of sequences */ public int convertPixelsToSequences(int y) { return Math.round((float) y / viewstyle.getCharHeight()); } /** * Convert number of sequences s to a height in viewport pixels * * @param s * number of sequences * @return number of pixels */ public int convertSequencesToPixels(int s) { return (s * viewstyle.getCharHeight()); } /** * Convert number of residues r to a width in viewport pixels * * @param r * number of residues * @return number of pixels */ public int convertResiduesToPixels(int r) { return (r * viewstyle.getCharWidth()); } public void setHiddenColumns(ColumnSelection colsel) { this.colSel = colsel; } public ColumnSelection getColumnSelection() { return colSel; } public void setColumnSelection(ColumnSelection colSel) { this.colSel = colSel; if (colSel != null) { // updateHiddenColumns(); - does nothing } isColSelChanged(true); } public boolean hasHiddenColumns() { return colSel != null && colSel.hasHiddenColumns(); } /** * checks current colsel against record of last hash value, and optionally * updates record. * * @param b * update the record of last hash value * @return true if colsel changed since last call (when b is true) */ public boolean isColSelChanged(boolean b) { int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode(); if (hc != -1 && hc != colselhash) { if (b) { colselhash = hc; } return true; } return false; } public void hideColumns(int start, int end) { if (start == end) { colSel.hideColumns(start); } else { colSel.hideColumns(start, end); } isColSelChanged(true); } public void showColumn(int col) { colSel.revealHiddenColumns(col); isColSelChanged(true); } public void showAllHiddenColumns() { colSel.revealAllHiddenColumns(); isColSelChanged(true); } public void invertColumnSelection() { colSel.invertColumnSelection(0, al.getWidth()); } public List getVisibleRegionBoundaries(int min, int max) { ArrayList regions = new ArrayList(); int start = min; int end = max; do { if (hasHiddenColumns()) { if (start == 0) { start = colSel.adjustForHiddenColumns(start); } end = colSel.getHiddenBoundaryRight(start); if (start == end) { end = max; } if (end > max) { end = max; } } regions.add(new int[] { start, end }); if (hasHiddenColumns()) { start = colSel.adjustForHiddenColumns(end); start = colSel.getHiddenBoundaryLeft(start) + 1; } } while (end < max); int[][] startEnd = new int[regions.size()][2]; return regions; } /** * synthesize a column selection if none exists so it covers the given * selection group. if wholewidth is false, no column selection is made if the * selection group covers the whole alignment width. * * @param sg * @param wholewidth */ public void expandColSelection(SequenceGroup sg, boolean wholewidth) { int sgs, sge; if (sg != null && (sgs = sg.getStartRes()) >= 0 && sg.getStartRes() <= (sge = sg.getEndRes())) { if (!wholewidth && al.getWidth() == (1 + sge - sgs)) { // do nothing return; } if (colSel == null) { colSel = new ColumnSelection(); } for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++) { colSel.addElement(cspos); } } } public List getVisibleAlignmentAnnotation( boolean selectedOnly, SequenceGroup selectionGroup) { ArrayList ala = new ArrayList(); AlignmentAnnotation[] aa; if ((aa = al.getAlignmentAnnotation()) != null) { for (AlignmentAnnotation annot : aa) { AlignmentAnnotation clone = new AlignmentAnnotation(annot); if (selectedOnly && selectionGroup != null) { colSel.makeVisibleAnnotation(selectionGroup.getStartRes(), selectionGroup.getEndRes(), clone); } else { colSel.makeVisibleAnnotation(clone); } ala.add(clone); } } return ala; } public String[] getVisibleSequenceStrings(int start, int end, SequenceI[] seqs) { return colSel.getVisibleSequenceStrings(start, end, seqs); } /** * Set visibility for any annotations for the given sequence. * * @param sequenceI */ protected void setSequenceAnnotationsVisible(SequenceI sequenceI, boolean visible) { AlignmentAnnotation[] anns = al.getAlignmentAnnotation(); if (anns != null) { for (AlignmentAnnotation ann : anns) { if (ann.sequenceRef == sequenceI) { ann.visible = visible; } } } } public void setHiddenRepSequences( Map hiddenRepSequences) { this.hiddenRepSequences = hiddenRepSequences; } public Map getHiddenRepSequences() { return hiddenRepSequences; } // common hide/show seq stuff public SequenceGroup showAllHiddenSeqs(SequenceGroup selectionGroup) { if (al.getHiddenSequences().getSize() > 0) { if (selectionGroup == null) { selectionGroup = new SequenceGroup(); selectionGroup.setEndRes(al.getWidth() - 1); } List tmp = al.getHiddenSequences().showAll( hiddenRepSequences); for (SequenceI seq : tmp) { selectionGroup.addSequence(seq, false); setSequenceAnnotationsVisible(seq, true); } hiddenRepSequences = null; firePropertyChange("alignment", null, al.getSequences()); // used to set hasHiddenRows/hiddenRepSequences here, after the property // changed event sendSelection(); } } public void showSequence(int index, SequenceGroup selectionGroup) { List tmp = al.getHiddenSequences().showSequence(index, hiddenRepSequences); if (tmp.size() > 0) { if (selectionGroup == null) { selectionGroup = new SequenceGroup(); selectionGroup.setEndRes(al.getWidth() - 1); } for (SequenceI seq : tmp) { selectionGroup.addSequence(seq, false); setSequenceAnnotationsVisible(seq, true); } firePropertyChange("alignment", null, al.getSequences()); sendSelection(); } } public void hideAllSelectedSeqs(SequenceGroup selectionGroup) { if (selectionGroup == null || selectionGroup.getSize() < 1) { return; } SequenceI[] seqs = selectionGroup.getSequencesInOrder(al); hideSequence(seqs); setSelectionGroup(null); } public void hideSequence(SequenceI[] seq) { if (seq != null) { for (int i = 0; i < seq.length; i++) { al.getHiddenSequences().hideSequence(seq[i]); setSequenceAnnotationsVisible(seq[i], false); } firePropertyChange("alignment", null, al.getSequences()); } } /** * Hides the specified sequence, or the sequences it represents * * @param sequence * the sequence to hide, or keep as representative * @param representGroup * if true, hide the current selection group except for the * representative sequence */ public void hideSequences(SequenceI sequence, boolean representGroup, SequenceGroup selectionGroup) { if (selectionGroup == null || selectionGroup.getSize() < 1) { hideSequence(new SequenceI[] { sequence }); return; } if (representGroup) { hideRepSequences(sequence, selectionGroup); setSelectionGroup(null); return; } int gsize = selectionGroup.getSize(); SequenceI[] hseqs = selectionGroup.getSequences().toArray( new SequenceI[gsize]); hideSequence(hseqs); setSelectionGroup(null); sendSelection(); } public void hideRepSequences(SequenceI repSequence, SequenceGroup sg) { int sSize = sg.getSize(); if (sSize < 2) { return; } if (hiddenRepSequences == null) { hiddenRepSequences = new Hashtable(); } hiddenRepSequences.put(repSequence, sg); // Hide all sequences except the repSequence SequenceI[] seqs = new SequenceI[sSize - 1]; int index = 0; for (int i = 0; i < sSize; i++) { if (sg.getSequenceAt(i) != repSequence) { if (index == sSize - 1) { return; } seqs[index++] = sg.getSequenceAt(i); } } sg.setSeqrep(repSequence); // note: not done in 2.7applet sg.setHidereps(true); // note: not done in 2.7applet hideSequence(seqs); } /** * * @param seq * @return true if there are sequences represented by this sequence that are * currently hidden */ public boolean isHiddenRepSequence(SequenceI seq) { return (hiddenRepSequences != null && hiddenRepSequences .containsKey(seq)); } /** * * @param seq * @return null or a sequence group containing the sequences that seq * represents */ public SequenceGroup getRepresentedSequences(SequenceI seq) { return (SequenceGroup) (hiddenRepSequences == null ? null : hiddenRepSequences.get(seq)); } public int adjustForHiddenSeqs(int alignmentIndex) { return al.getHiddenSequences().adjustForHiddenSeqs(alignmentIndex); } }