Merge branch 'features/r2_11_2_alphafold/JAL-629' into features/JAL-4134_treeviewerfo...
[jalview.git] / src / jalview / gui / AnnotationPanel.java
index c3b44ce..b112383 100755 (executable)
@@ -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
@@ -588,8 +592,9 @@ 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;
@@ -598,6 +603,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         }
         else
         {
+          GraphLine thr = aa[graphStretch].getThreshold();
+          
           int currentX = getColumnForXPos(evt.getX());
           ContactListI forCurrentX = av.getContactList(aa[graphStretch],
                   currentX);
@@ -607,14 +614,107 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
                     aa[graphStretch].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);
-            for (int c = fr; c <= to; c++)
+
+            if (evt.isControlDown())
             {
-              av.getColumnSelection().addElement(c);
+              ContactMatrixI matrix = av.getContactMatrix(aa[graphStretch]);
+              
+              if (matrix != null)
+              {
+                // simplest approach is to select all group containing column
+                if (matrix.hasGroups())
+                {
+                  SequenceI rseq = aa[graphStretch].sequenceRef;
+                  BitSet grp = matrix.getGroupsFor(currentX);
+                  for (int c=fr;c<=to; 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(aa[graphStretch].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);
           }
         }
       }
@@ -784,7 +884,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
          * 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
@@ -1107,7 +1207,7 @@ 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)
@@ -1284,24 +1384,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();