X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAnnotationPanel.java;h=c7751e3cdceb43415f07cf93ab42b825238e4db8;hb=7340ceba8e1dafe0a3c9ce14ca4c1b1c29a25e0d;hp=7f606c82d96e3c140618d5269137b506d9e4d85e;hpb=0b3980f60e9cd7c71a84cbcdfd9008f5116e86fb;p=jalview.git diff --git a/src/jalview/gui/AnnotationPanel.java b/src/jalview/gui/AnnotationPanel.java index 7f606c8..c7751e3 100755 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@ -41,6 +41,7 @@ import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collections; import java.util.List; @@ -56,7 +57,9 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.ContactListI; +import jalview.datamodel.ContactMatrixI; import jalview.datamodel.ContactRange; +import jalview.datamodel.GraphLine; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import jalview.gui.JalviewColourChooser.ColourChooserListener; @@ -69,6 +72,7 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.viewmodel.ViewportListenerI; import jalview.viewmodel.ViewportRanges; +import jalview.ws.datamodel.alphafold.PAEContactMatrix; /** * AnnotationPanel displays visible portion of annotation rows below unwrapped @@ -150,6 +154,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, private MouseWheelListener[] _mwl; + private boolean notJustOne; + /** * Creates a new AnnotationPanel object. * @@ -586,43 +592,163 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, if (graphStretch != -1) { - if (aa[graphStretch].graph == AlignmentAnnotation.CUSTOMRENDERER) + if (aa[graphStretch].graph == AlignmentAnnotation.CONTACT_MAP) { + // data in row has position on y as well as x axis if (evt.isAltDown() || evt.isAltGraphDown()) { dragMode = DragMode.MatrixSelect; firstDragX = mouseDragLastX; firstDragY = mouseDragLastY; } - else + } + } + else + { + // no row (or row that can be adjusted) was pressed. Simulate a ruler click + ap.getScalePanel().mousePressed(evt); + } + } + + /** + * checks whether the annotation row under the mouse click evt's handles the + * event + * + * @param evt + * @return false if evt was not handled + */ + boolean matrix_clicked(MouseEvent evt) + { + int[] rowIndex = getRowIndexAndOffset(evt.getY(), + av.getAlignment().getAlignmentAnnotation()); + int yOffset = rowIndex[1]; + + if (rowIndex == null) + { + System.err.println("IMPLEMENTATION ERROR: matrix click out of range."); + } + AlignmentAnnotation clicked = av.getAlignment() + .getAlignmentAnnotation()[rowIndex[0]]; + if (clicked.graph != AlignmentAnnotation.CONTACT_MAP) + { + return false; + } + + // TODO - use existing threshold to select related sections of matrix + GraphLine thr = clicked.getThreshold(); + + int currentX = getColumnForXPos(evt.getX()); + ContactListI forCurrentX = av.getContactList(clicked, currentX); + if (forCurrentX != null) + { + ContactGeometry cXcgeom = new ContactGeometry(forCurrentX, + clicked.graphHeight); + ContactGeometry.contactInterval cXci = cXcgeom.mapFor(yOffset, + yOffset); + /** + * start and end range corresponding to the row range under the mouse at + * column currentX + */ + int fr, to; + fr = Math.min(cXci.cStart, cXci.cEnd); + to = Math.max(cXci.cStart, cXci.cEnd); + + if (evt.isControlDown()) + { + ContactMatrixI matrix = av.getContactMatrix(clicked); + + if (matrix != null) { - int currentX = getColumnForXPos(evt.getX()); - ContactListI forCurrentX = av.getContactList(aa[graphStretch], - currentX); - if (forCurrentX != null) + // simplest approach is to select all group containing column + if (matrix.hasGroups()) { - ContactGeometry cXcgeom = new ContactGeometry(forCurrentX, - aa[graphStretch].graphHeight); - ContactGeometry.contactInterval cXci = cXcgeom.mapFor(yOffset, - yOffset); - int fr, to; - fr = Math.min(cXci.cStart, cXci.cEnd); - to = Math.max(cXci.cStart, cXci.cEnd); + SequenceI rseq = clicked.sequenceRef; + BitSet grp = matrix.getGroupsFor(currentX); for (int c = fr; c <= to; c++) { - av.getColumnSelection().addElement(c); + BitSet additionalGrp = matrix.getGroupsFor(c); + grp.or(additionalGrp); + } + HiddenColumns hc = av.getAlignment().getHiddenColumns(); + for (int p = grp.nextSetBit(0); p >= 0; p = grp + .nextSetBit(p + 1)) + { + int offp = (rseq != null) + ? rseq.findIndex(rseq.getStart() - 1 + p) + : p; + + if (!av.hasHiddenColumns() || hc.isVisible(offp)) + { + av.getColumnSelection().addElement(offp); + } + } + } + // possible alternative for interactive selection - threshold + // gives 'ceiling' for forming a cluster + // when a row+column is selected, farthest common ancestor less + // than thr is used to compute cluster + + } + } + else + { + // select corresponding range in segment under mouse + { + for (int c = fr; c <= to; c++) + { + av.getColumnSelection().addElement(c); + } + av.getColumnSelection().addElement(currentX); + } + // PAE SPECIFIC + // and also select everything lower than the max range adjacent + // (kind of works) + if (PAEContactMatrix.PAEMATRIX.equals(clicked.getCalcId())) + { + int c = fr - 1; + ContactRange cr = forCurrentX.getRangeFor(fr, to); + double cval; + // TODO: could use GraphLine instead of arbitrary picking + // TODO: could report mean/median/variance for partitions + // (contiguous selected vs unselected regions and inter-contig + // regions) + // controls feathering - what other elements in row/column + // should we select + double thresh = cr.getMean() + (cr.getMax() - cr.getMean()) * .15; + while (c > 0) + { + cval = forCurrentX.getContactAt(c); + if (// cr.getMin() <= cval && + cval <= thresh) + { + av.getColumnSelection().addElement(c--); + } + else + { + break; + } + } + c = to; + while (c < forCurrentX.getContactHeight()) + { + cval = forCurrentX.getContactAt(c); + if (// cr.getMin() <= cval && + cval <= thresh) + { + av.getColumnSelection().addElement(c++); + } + else + { + break; } - av.getColumnSelection().addElement(currentX); } } } } - else - { - ap.getScalePanel().mousePressed(evt); - } - } + ap.paintAlignment(false, false); + return true; + } /** * Construct and display a context menu at the right-click position * @@ -695,7 +821,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, ap.adjustAnnotationHeight(); } dragMode = DragMode.Undefined; - ap.getScalePanel().mouseReleased(evt); + if (!matrix_clicked(evt)) + { + ap.getScalePanel().mouseReleased(evt); + } /* * isPopupTrigger is set in mouseReleased on Windows @@ -776,12 +905,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, * mostly vertical drag */ dragMode = DragMode.Resize; + notJustOne = evt.isShiftDown(); /* * but could also be a matrix drag */ if ((evt.isAltDown() || evt.isAltGraphDown()) && (av.getAlignment() - .getAlignmentAnnotation()[graphStretch].graph == AlignmentAnnotation.CUSTOMRENDERER)) + .getAlignmentAnnotation()[graphStretch].graph == AlignmentAnnotation.CONTACT_MAP)) { /* * dragging in a matrix @@ -816,7 +946,20 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, AlignmentAnnotation graphAnnotation = av.getAlignment() .getAlignmentAnnotation()[graphStretch]; int newHeight = Math.max(0, graphAnnotation.graphHeight + deltaY); - graphAnnotation.graphHeight = newHeight; + if (notJustOne) + { + for (AlignmentAnnotation similar : av.getAlignment() + .findAnnotations(null, graphAnnotation.getCalcId(), + graphAnnotation.label)) + { + similar.graphHeight = newHeight; + } + + } + else + { + graphAnnotation.graphHeight = newHeight; + } adjustPanelHeight(); ap.paintAlignment(false, false); } @@ -852,7 +995,11 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, */ int fromY = Math.min(firstDragY, evt.getY()); int toY = Math.max(firstDragY, evt.getY()); + int fromX = Math.min(firstDragX, evt.getX()); + int toX = Math.max(firstDragX, evt.getX()); + int deltaY = toY - fromY; + int deltaX = toX - fromX; int[] rowIndex = getRowIndexAndOffset(fromY, av.getAlignment().getAlignmentAnnotation()); @@ -873,41 +1020,59 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, AlignmentAnnotation cma = av.getAlignment() .getAlignmentAnnotation()[rowIndex[0]]; - int fromXp = Math.min(firstDragX, evt.getX()); - int toXp = Math.max(firstDragX, evt.getX()); - int lastX = getColumnForXPos(fromXp); - int currentX = getColumnForXPos(toXp); - ContactListI forLastX = av.getContactList(cma, lastX); - ContactListI forCurrentX = av.getContactList(cma, currentX); - if (forLastX != null && forCurrentX != null) + int lastX = getColumnForXPos(fromX); + int currentX = getColumnForXPos(toX); + int fromXc = Math.min(lastX, currentX); + int toXc = Math.max(lastX, currentX); + ContactListI forFromX = av.getContactList(cma, fromXc); + ContactListI forToX = av.getContactList(cma, toXc); + + if (forFromX != null && forToX != null) { - ContactGeometry lastXcgeom = new ContactGeometry(forLastX, + ContactGeometry lastXcgeom = new ContactGeometry(forFromX, cma.graphHeight); - ContactGeometry.contactInterval lastXci = lastXcgeom.mapFor( - rowIndex[1], - rowIndex[1] + ((fromY == firstDragY) ? -deltaY : deltaY)); - ContactGeometry cXcgeom = new ContactGeometry(forCurrentX, + ContactGeometry.contactInterval lastXci = lastXcgeom + .mapFor(rowIndex[1], rowIndex[1] - deltaY); + + ContactGeometry cXcgeom = new ContactGeometry(forToX, cma.graphHeight); ContactGeometry.contactInterval cXci = cXcgeom.mapFor(rowIndex[1], - rowIndex[1] + deltaY); + rowIndex[1] - deltaY); + // mark rectangular region formed by drag - System.err.println("Matrix Selection from last(" + lastXci.cStart - + "," + lastXci.cEnd + ") to cur(" + cXci.cStart + "," - + cXci.cEnd + ")"); + System.err.println("Matrix Selection from last(" + fromXc + ",[" + + lastXci.cStart + "," + lastXci.cEnd + "]) to cur(" + toXc + + ",[" + cXci.cStart + "," + cXci.cEnd + "])"); int fr, to; fr = Math.min(lastXci.cStart, lastXci.cEnd); to = Math.max(lastXci.cStart, lastXci.cEnd); System.err.println("Marking " + fr + " to " + to); for (int c = fr; c <= to; c++) { - av.getColumnSelection().addElement(c); + if (cma.sequenceRef != null) + { + int col = cma.sequenceRef.findIndex(c); + av.getColumnSelection().addElement(col); + } + else + { + av.getColumnSelection().addElement(c); + } } fr = Math.min(cXci.cStart, cXci.cEnd); to = Math.max(cXci.cStart, cXci.cEnd); System.err.println("Marking " + fr + " to " + to); for (int c = fr; c <= to; c++) { - av.getColumnSelection().addElement(c); + if (cma.sequenceRef != null) + { + int col = cma.sequenceRef.findIndex(c); + av.getColumnSelection().addElement(col); + } + else + { + av.getColumnSelection().addElement(c); + } } fr = Math.min(lastX, currentX); to = Math.max(lastX, currentX); @@ -997,15 +1162,14 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, static int[] getRowIndexAndOffset(int yPos, AlignmentAnnotation[] aa) { int[] res = new int[2]; + res[0] = -1; + res[1] = 0; if (aa == null) { - res[0] = -1; - res[1] = 0; return res; } int row = -1; int height = 0, lheight = 0; - for (int i = 0; i < aa.length; i++) { if (aa[i].visible) @@ -1070,20 +1234,22 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, tooltip = ann.annotations[column].description; } // TODO abstract tooltip generator so different implementations can be built - if (ann.graph == AlignmentAnnotation.CUSTOMRENDERER) + if (ann.graph == AlignmentAnnotation.CONTACT_MAP) { ContactListI clist = av.getContactList(ann, column); if (clist != null) { ContactGeometry cgeom = new ContactGeometry(clist, ann.graphHeight); - ContactGeometry.contactInterval ci = cgeom.mapFor(rowAndOffset, - rowAndOffset); + ContactGeometry.contactInterval ci = cgeom.mapFor(rowAndOffset); ContactRange cr = clist.getRangeFor(ci.cStart, ci.cEnd); - tooltip = "Contact from " + ci.cStart + " to " + ci.cEnd - + "
Mean:" + cr.getMean(); - - // ap.getStructureSelectionManager().mouseOverSequence(ann.sequenceRef, - // new int[] {column, ci.cStart,ci.cEnd}, -1, null) + tooltip = "Contact from " + clist.getPosition() + ", [" + ci.cStart + + " - " + ci.cEnd + "]" + "
Mean:" + cr.getMean(); + int col = ann.sequenceRef.findPosition(column); + ap.getStructureSelectionManager() + .highlightPositionsOn(ann.sequenceRef, new int[][] + { new int[] { col, col }, + new int[] + { ci.cStart, ci.cEnd } }, null); } } return tooltip; @@ -1245,24 +1411,37 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, if (image == null || imgWidth != image.getWidth(this) || image.getHeight(this) != getHeight()) { - try - { - image = new BufferedImage(imgWidth, - ap.getAnnotationPanel().getHeight(), - BufferedImage.TYPE_INT_RGB); - } catch (OutOfMemoryError oom) + boolean tried = false; + image = null; + while (image == null && !tried) { try { - System.gc(); - } catch (Exception x) + image = new BufferedImage(imgWidth, + ap.getAnnotationPanel().getHeight(), + BufferedImage.TYPE_INT_RGB); + tried = true; + } catch (IllegalArgumentException exc) { + System.err.println( + "Serious issue with viewport geometry imgWidth requested was " + + imgWidth); + return; + } catch (OutOfMemoryError oom) + { + try + { + System.gc(); + } catch (Exception x) + { + } + ; + new OOMWarning( + "Couldn't allocate memory to redraw screen. Please restart Jalview", + oom); + return; } - ; - new OOMWarning( - "Couldn't allocate memory to redraw screen. Please restart Jalview", - oom); - return; + } gg = (Graphics2D) image.getGraphics();