From b70c7ff4b002103401ccceb917114b954e18d50c Mon Sep 17 00:00:00 2001 From: kiramt Date: Wed, 26 Apr 2017 14:35:14 +0100 Subject: [PATCH] JAL-2388 last separation of hidden columns/col selection --- src/jalview/appletgui/SeqPanel.java | 3 +- src/jalview/datamodel/ColumnSelection.java | 277 ++--------------------- src/jalview/datamodel/HiddenColumns.java | 193 +++++++++++++++- src/jalview/gui/SeqPanel.java | 3 +- src/jalview/ws/jws1/JPredThread.java | 9 +- test/jalview/datamodel/ColumnSelectionTest.java | 24 ++ 6 files changed, 239 insertions(+), 270 deletions(-) diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index ceae253..69a0dd0 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -1878,7 +1878,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, } else { - av.getColumnSelection().setElementsFrom(colsel); + av.getColumnSelection().setElementsFrom(colsel, + av.getAlignment().getHiddenColumns()); } } repaint |= av.isColSelChanged(true); diff --git a/src/jalview/datamodel/ColumnSelection.java b/src/jalview/datamodel/ColumnSelection.java index 4d69fa4..eb2d174 100644 --- a/src/jalview/datamodel/ColumnSelection.java +++ b/src/jalview/datamodel/ColumnSelection.java @@ -20,7 +20,6 @@ */ package jalview.datamodel; -import jalview.util.ShiftList; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField; @@ -266,8 +265,6 @@ public class ColumnSelection IntList selection = new IntList(); - HiddenColumns hiddenColumns = new HiddenColumns(); - /** * Add a column to the selection * @@ -391,93 +388,6 @@ public class ColumnSelection return selection.getMinColumn(); } - /** - * propagate shift in alignment columns to column selection - * - * @param start - * beginning of edit - * @param left - * shift in edit (+ve for removal, or -ve for inserts) - */ - /* public List compensateForEdit(int start, int change) - { - selection.compensateForEdits(start, change); - return hiddenColumns.compensateForEdit(start, change, this); - } - */ - /** - * propagate shift in alignment columns to column selection special version of - * compensateForEdit - allowing for edits within hidden regions - * - * @param start - * beginning of edit - * @param left - * shift in edit (+ve for removal, or -ve for inserts) - */ - private void compensateForDelEdits(int start, int change) - { - selection.compensateForEdits(start, change); - hiddenColumns.compensateForDelEdits(start, change); - } - - /** - * Adjust hidden column boundaries based on a series of column additions or - * deletions in visible regions. - * - * @param shiftrecord - * @return - */ - private ShiftList compensateForEdits(ShiftList shiftrecord) - { - if (shiftrecord != null) - { - final List shifts = shiftrecord.getShifts(); - if (shifts != null && shifts.size() > 0) - { - int shifted = 0; - for (int i = 0, j = shifts.size(); i < j; i++) - { - int[] sh = shifts.get(i); - compensateForDelEdits(shifted + sh[0], sh[1]); - shifted -= sh[1]; - } - } - return shiftrecord.getInverse(); - } - return null; - } - - - /** - * remove any hiddenColumns or selected columns and shift remaining based on a - * series of position, range deletions. - * - * @param deletions - */ - private void pruneDeletions(ShiftList deletions) - { - if (deletions != null) - { - final List shifts = deletions.getShifts(); - if (shifts != null && shifts.size() > 0) - { - hiddenColumns.pruneDeletions(shifts); - - if (selection != null && selection.size() > 0) - { - selection.pruneColumnList(shifts); - if (selection != null && selection.size() == 0) - { - selection = null; - } - } - // and shift the rest. - this.compensateForEdits(deletions); - } - } - } - - public void hideSelectedColumns(AlignmentI al) { synchronized (selection) @@ -590,33 +500,13 @@ public class ColumnSelection } /** - * add in any unselected columns from the given column selection, excluding - * any that are hidden. - * - * @param colsel - */ - public void addElementsFrom(ColumnSelection colsel) - { - if (colsel != null && !colsel.isEmpty()) - { - for (Integer col : colsel.getSelected()) - { - if (hiddenColumns != null - && hiddenColumns.isVisible(col.intValue())) - { - selection.add(col); - } - } - } - } - - /** - * set the selected columns the given column selection, excluding any columns - * that are hidden. + * set the selected columns to the given column selection, excluding any + * columns that are hidden. * * @param colsel */ - public void setElementsFrom(ColumnSelection colsel) + public void setElementsFrom(ColumnSelection colsel, + HiddenColumns hiddenColumns) { selection = new IntList(); if (colsel.selection != null && colsel.selection.size() > 0) @@ -624,162 +514,27 @@ public class ColumnSelection if (hiddenColumns.hasHidden()) { // only select visible columns in this columns selection - addElementsFrom(colsel); - } - else - { - // add everything regardless for (Integer col : colsel.getSelected()) { - addElement(col); - } - } - } - } - - /** - * Add gaps into the sequences aligned to profileseq under the given - * AlignmentView - * - * @param profileseq - * @param al - * - alignment to have gaps inserted into it - * @param input - * - alignment view where sequence corresponding to profileseq is - * first entry - * @return new Column selection for new alignment view, with insertions into - * profileseq marked as hidden. - */ - public static ColumnSelection propagateInsertions(SequenceI profileseq, - AlignmentI al, AlignmentView input) - { - int profsqpos = 0; - - // return propagateInsertions(profileseq, al, ) - char gc = al.getGapCharacter(); - Object[] alandcolsel = input.getAlignmentAndHiddenColumns(gc); - ColumnSelection nview = (ColumnSelection) alandcolsel[1]; - SequenceI origseq = ((SequenceI[]) alandcolsel[0])[profsqpos]; - nview.propagateInsertions(profileseq, al, origseq); - return nview; - } - - /** - * - * @param profileseq - * - sequence in al which corresponds to origseq - * @param al - * - alignment which is to have gaps inserted into it - * @param origseq - * - sequence corresponding to profileseq which defines gap map for - * modifying al - */ - private void propagateInsertions(SequenceI profileseq, AlignmentI al, - SequenceI origseq) - { - char gc = al.getGapCharacter(); - // recover mapping between sequence's non-gap positions and positions - // mapping to view. - pruneDeletions(ShiftList.parseMap(origseq.gapMap())); - int[] viscontigs = hiddenColumns.getVisibleContigs(0, - profileseq.getLength()); - int spos = 0; - int offset = 0; - - // add profile to visible contigs - for (int v = 0; v < viscontigs.length; v += 2) - { - if (viscontigs[v] > spos) - { - StringBuffer sb = new StringBuffer(); - for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++) - { - sb.append(gc); - } - for (int s = 0, ns = al.getHeight(); s < ns; s++) - { - SequenceI sqobj = al.getSequenceAt(s); - if (sqobj != profileseq) + if (hiddenColumns != null + && hiddenColumns.isVisible(col.intValue())) { - String sq = al.getSequenceAt(s).getSequenceAsString(); - if (sq.length() <= spos + offset) - { - // pad sequence - int diff = spos + offset - sq.length() - 1; - if (diff > 0) - { - // pad gaps - sq = sq + sb; - while ((diff = spos + offset - sq.length() - 1) > 0) - { - // sq = sq - // + ((diff >= sb.length()) ? sb.toString() : sb - // .substring(0, diff)); - if (diff >= sb.length()) - { - sq += sb.toString(); - } - else - { - char[] buf = new char[diff]; - sb.getChars(0, diff, buf, 0); - sq += buf.toString(); - } - } - } - sq += sb.toString(); - } - else - { - al.getSequenceAt(s).setSequence( - sq.substring(0, spos + offset) + sb.toString() - + sq.substring(spos + offset)); - } + selection.add(col); } } - // offset+=sb.length(); - } - spos = viscontigs[v + 1] + 1; - } - if ((offset + spos) < profileseq.getLength()) - { - // pad the final region with gaps. - StringBuffer sb = new StringBuffer(); - for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++) - { - sb.append(gc); } - for (int s = 0, ns = al.getHeight(); s < ns; s++) + else { - SequenceI sqobj = al.getSequenceAt(s); - if (sqobj == profileseq) - { - continue; - } - String sq = sqobj.getSequenceAsString(); - // pad sequence - int diff = origseq.getLength() - sq.length(); - while (diff > 0) + // add everything regardless + for (Integer col : colsel.getSelected()) { - // sq = sq - // + ((diff >= sb.length()) ? sb.toString() : sb - // .substring(0, diff)); - if (diff >= sb.length()) - { - sq += sb.toString(); - } - else - { - char[] buf = new char[diff]; - sb.getChars(0, diff, buf, 0); - sq += buf.toString(); - } - diff = origseq.getLength() - sq.length(); + addElement(col); } } } } + /** * * @return true if there are columns marked @@ -796,7 +551,6 @@ public class ColumnSelection { // JBPNote - this method needs to be refactored to become independent of // viewmodel package - hiddenColumns.revealAllHiddenColumns(this); this.clear(); int count = 0; do @@ -879,13 +633,12 @@ public class ColumnSelection } /** - * Returns a hashCode built from selected columns and hidden column ranges + * Returns a hashCode built from selected columns ranges */ @Override public int hashCode() { - int hashCode = selection.hashCode(); - return hiddenColumns.hashCode(hashCode); + return selection.hashCode(); } /** @@ -916,7 +669,7 @@ public class ColumnSelection return false; } - return this.hiddenColumns.equals(that.hiddenColumns); + return true; } /** diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 0b7e246..1abd04b 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -1,6 +1,7 @@ package jalview.datamodel; import jalview.util.Comparison; +import jalview.util.ShiftList; import java.util.ArrayList; import java.util.Collections; @@ -1031,7 +1032,197 @@ public class HiddenColumns } /** - * Returns a hashCode built from selected columns and hidden column ranges + * Add gaps into the sequences aligned to profileseq under the given + * AlignmentView + * + * @param profileseq + * @param al + * - alignment to have gaps inserted into it + * @param input + * - alignment view where sequence corresponding to profileseq is + * first entry + * @return new HiddenColumns for new alignment view, with insertions into + * profileseq marked as hidden. + */ + public static HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentI al, AlignmentView input) + { + int profsqpos = 0; + + char gc = al.getGapCharacter(); + Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc); + HiddenColumns nview = (HiddenColumns) alandhidden[1]; + SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos]; + nview.propagateInsertions(profileseq, al, origseq); + return nview; + } + + /** + * + * @param profileseq + * - sequence in al which corresponds to origseq + * @param al + * - alignment which is to have gaps inserted into it + * @param origseq + * - sequence corresponding to profileseq which defines gap map for + * modifying al + */ + private void propagateInsertions(SequenceI profileseq, AlignmentI al, + SequenceI origseq) + { + char gc = al.getGapCharacter(); + // recover mapping between sequence's non-gap positions and positions + // mapping to view. + pruneDeletions(ShiftList.parseMap(origseq.gapMap())); + int[] viscontigs = al.getHiddenColumns().getVisibleContigs(0, + profileseq.getLength()); + int spos = 0; + int offset = 0; + + // add profile to visible contigs + for (int v = 0; v < viscontigs.length; v += 2) + { + if (viscontigs[v] > spos) + { + StringBuffer sb = new StringBuffer(); + for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++) + { + sb.append(gc); + } + for (int s = 0, ns = al.getHeight(); s < ns; s++) + { + SequenceI sqobj = al.getSequenceAt(s); + if (sqobj != profileseq) + { + String sq = al.getSequenceAt(s).getSequenceAsString(); + if (sq.length() <= spos + offset) + { + // pad sequence + int diff = spos + offset - sq.length() - 1; + if (diff > 0) + { + // pad gaps + sq = sq + sb; + while ((diff = spos + offset - sq.length() - 1) > 0) + { + // sq = sq + // + ((diff >= sb.length()) ? sb.toString() : sb + // .substring(0, diff)); + if (diff >= sb.length()) + { + sq += sb.toString(); + } + else + { + char[] buf = new char[diff]; + sb.getChars(0, diff, buf, 0); + sq += buf.toString(); + } + } + } + sq += sb.toString(); + } + else + { + al.getSequenceAt(s).setSequence( + sq.substring(0, spos + offset) + sb.toString() + + sq.substring(spos + offset)); + } + } + } + // offset+=sb.length(); + } + spos = viscontigs[v + 1] + 1; + } + if ((offset + spos) < profileseq.getLength()) + { + // pad the final region with gaps. + StringBuffer sb = new StringBuffer(); + for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++) + { + sb.append(gc); + } + for (int s = 0, ns = al.getHeight(); s < ns; s++) + { + SequenceI sqobj = al.getSequenceAt(s); + if (sqobj == profileseq) + { + continue; + } + String sq = sqobj.getSequenceAsString(); + // pad sequence + int diff = origseq.getLength() - sq.length(); + while (diff > 0) + { + // sq = sq + // + ((diff >= sb.length()) ? sb.toString() : sb + // .substring(0, diff)); + if (diff >= sb.length()) + { + sq += sb.toString(); + } + else + { + char[] buf = new char[diff]; + sb.getChars(0, diff, buf, 0); + sq += buf.toString(); + } + diff = origseq.getLength() - sq.length(); + } + } + } + } + + /** + * remove any hiddenColumns or selected columns and shift remaining based on a + * series of position, range deletions. + * + * @param deletions + */ + private void pruneDeletions(ShiftList deletions) + { + if (deletions != null) + { + final List shifts = deletions.getShifts(); + if (shifts != null && shifts.size() > 0) + { + pruneDeletions(shifts); + + // and shift the rest. + this.compensateForEdits(deletions); + } + } + } + + /** + * Adjust hidden column boundaries based on a series of column additions or + * deletions in visible regions. + * + * @param shiftrecord + * @return + */ + private ShiftList compensateForEdits(ShiftList shiftrecord) + { + if (shiftrecord != null) + { + final List shifts = shiftrecord.getShifts(); + if (shifts != null && shifts.size() > 0) + { + int shifted = 0; + for (int i = 0, j = shifts.size(); i < j; i++) + { + int[] sh = shifts.get(i); + compensateForDelEdits(shifted + sh[0], sh[1]); + shifted -= sh[1]; + } + } + return shiftrecord.getInverse(); + } + return null; + } + + /** + * Returns a hashCode built from hidden column ranges */ public int hashCode(int hc) { diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 063ab7d..31fe2b6 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -2044,7 +2044,8 @@ public class SeqPanel extends JPanel implements MouseListener, } else { - av.getColumnSelection().setElementsFrom(colsel); + av.getColumnSelection().setElementsFrom(colsel, + av.getAlignment().getHiddenColumns()); } } av.isColSelChanged(true); diff --git a/src/jalview/ws/jws1/JPredThread.java b/src/jalview/ws/jws1/JPredThread.java index 078f189..b0210d8 100644 --- a/src/jalview/ws/jws1/JPredThread.java +++ b/src/jalview/ws/jws1/JPredThread.java @@ -27,7 +27,6 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; -import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; @@ -115,7 +114,7 @@ class JPredThread extends JWS1Thread implements WSClientI return null; } AlignmentI al = null; - ColumnSelection alcsel = null; + HiddenColumns alhidden = null; int FirstSeq = -1; // the position of the query sequence in Alignment al JpredResult result = (JpredResult) this.result; @@ -145,7 +144,7 @@ class JPredThread extends JWS1Thread implements WSClientI .getAlignmentAndHiddenColumns(getGapChar()); sqs = (SequenceI[]) alandcolsel[0]; al = new Alignment(sqs); - alcsel = (ColumnSelection) alandcolsel[1]; + alhidden = (HiddenColumns) alandcolsel[1]; } else { @@ -238,7 +237,7 @@ class JPredThread extends JWS1Thread implements WSClientI { // Adjust input view for gaps // propagate insertions into profile - alcsel = ColumnSelection.propagateInsertions(profileseq, al, + alhidden = HiddenColumns.propagateInsertions(profileseq, al, input); } } @@ -253,7 +252,7 @@ class JPredThread extends JWS1Thread implements WSClientI alant.sequenceRef); } } - return new Object[] { al, alcsel }; // , FirstSeq, noMsa}; + return new Object[] { al, alhidden }; // , FirstSeq, noMsa}; } /** diff --git a/test/jalview/datamodel/ColumnSelectionTest.java b/test/jalview/datamodel/ColumnSelectionTest.java index e5f2daa..ce2949f 100644 --- a/test/jalview/datamodel/ColumnSelectionTest.java +++ b/test/jalview/datamodel/ColumnSelectionTest.java @@ -59,6 +59,30 @@ public class ColumnSelectionTest assertEquals("[2, 5, 3]", sel.toString()); } + @Test(groups = { "Functional" }) + public void testSetElementsFrom() + { + ColumnSelection fromcs = new ColumnSelection(); + ColumnSelection tocs = new ColumnSelection(); + HiddenColumns hidden = new HiddenColumns(); + + fromcs.addElement(2); + fromcs.addElement(3); + fromcs.addElement(5); + + tocs.setElementsFrom(fromcs, hidden); + assertTrue(tocs.equals(fromcs)); + + hidden.hideColumns(4, 6); + tocs.setElementsFrom(fromcs, hidden); + + // expect cols 2 and 3 to be selected but not 5 + ColumnSelection expectcs = new ColumnSelection(); + expectcs.addElement(2); + expectcs.addElement(3); + assertTrue(tocs.equals(expectcs)); + } + /** * Test the remove method - in particular to verify that remove(int i) removes * the element whose value is i, _NOT_ the i'th element. -- 1.7.10.2