Merge remote-tracking branch 'origin/bug/JAL-3049colourCellTooltip' into
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 5 Mar 2019 09:01:48 +0000 (09:01 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 5 Mar 2019 09:01:48 +0000 (09:01 +0000)
merge/JAL-3049

Conflicts:
src/jalview/api/FeatureColourI.java
src/jalview/schemes/FeatureColour.java
test/jalview/schemes/FeatureColourTest.java

src/jalview/api/FeatureColourI.java
src/jalview/gui/FeatureSettings.java
src/jalview/schemes/FeatureColour.java
test/jalview/gui/FeatureSettingsTest.java
test/jalview/schemes/FeatureColourTest.java

index 999104c..7bfd8a8 100644 (file)
@@ -204,4 +204,12 @@ public interface FeatureColourI
    * @return
    */
   boolean isOutwithThreshold(SequenceFeature sf);
+
+  /*
+   * Answers a human-readable text description of the colour, suitable for
+   * display as a tooltip, possibly internationalised for the user's locale.
+   * 
+   * @return
+   */
+  String getDescription();
 }
index 534a088..40e49fb 100644 (file)
@@ -24,6 +24,7 @@ import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
 import jalview.datamodel.features.FeatureMatcherI;
 import jalview.datamodel.features.FeatureMatcherSet;
 import jalview.datamodel.features.FeatureMatcherSetI;
@@ -92,6 +93,7 @@ import javax.swing.JSlider;
 import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingConstants;
+import javax.swing.border.Border;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.table.AbstractTableModel;
@@ -128,6 +130,8 @@ public class FeatureSettings extends JPanel
 
   private static final int MIN_HEIGHT = 400;
 
+  private final static String BASE_TOOLTIP = "Click to edit, right-click for menu";
+
   final FeatureRenderer fr;
 
   public final AlignFrame af;
@@ -197,19 +201,27 @@ public class FeatureSettings extends JPanel
 
     table = new JTable()
     {
+      static final String tt = "Click to edit, right-click for menu"; // todo i18n
+      
       @Override
       public String getToolTipText(MouseEvent e)
       {
         String tip = null;
         int column = table.columnAtPoint(e.getPoint());
+        int row = table.rowAtPoint(e.getPoint());
+
         switch (column)
         {
         case TYPE_COLUMN:
           tip = JvSwingUtils.wrapTooltip(true, MessageManager
                   .getString("label.feature_settings_click_drag"));
           break;
+        case COLOUR_COLUMN:
+          FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
+                  column);
+          tip = getColorTooltip(colour);
+          break;
         case FILTER_COLUMN:
-          int row = table.rowAtPoint(e.getPoint());
           FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
                   column);
           tip = o.isEmpty()
@@ -222,6 +234,21 @@ public class FeatureSettings extends JPanel
         }
         return tip;
       }
+
+      /**
+       * Position the tooltip at the bottom edge of, and half way across, the
+       * current cell
+       */
+      @Override
+      public Point getToolTipLocation(MouseEvent e)
+      {
+        Point point = e.getPoint();
+        int column = table.columnAtPoint(point);
+        int row = table.rowAtPoint(point);
+        Rectangle r = getCellRect(row, column, false);
+        Point loc = new Point(r.x + r.width / 2, r.y + r.height);
+        return loc;
+      }
     };
     JTableHeader tableHeader = table.getTableHeader();
     tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
@@ -1280,6 +1307,84 @@ public class FeatureSettings extends JPanel
     this.add(settingsPane);
   }
 
+  /**
+   * Answers a suitable tooltip to show on the colour cell of the table
+   * 
+   * @param fcol
+   * @return
+   */
+  public static String getColorTooltip(FeatureColourI fcol)
+  {
+    if (fcol == null)
+    {
+      return null;
+    }
+    if (fcol.isSimpleColour())
+    {
+      return BASE_TOOLTIP;
+    }
+    String description = fcol.getDescription();
+    description = description.replaceAll("<", "&lt;");
+    description = description.replaceAll(">", "&gt;");
+    StringBuilder tt = new StringBuilder(description);
+    tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
+    return JvSwingUtils.wrapTooltip(true, tt.toString());
+  }
+
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
+          int w, int h)
+  {
+    boolean thr = false;
+    StringBuilder tx = new StringBuilder();
+  
+    if (gcol.isColourByAttribute())
+    {
+      tx.append(FeatureMatcher
+              .toAttributeDisplayName(gcol.getAttributeName()));
+    }
+    else if (!gcol.isColourByLabel())
+    {
+      tx.append(MessageManager.getString("label.score"));
+    }
+    tx.append(" ");
+    if (gcol.isAboveThreshold())
+    {
+      thr = true;
+      tx.append(">");
+    }
+    if (gcol.isBelowThreshold())
+    {
+      thr = true;
+      tx.append("<");
+    }
+    if (gcol.isColourByLabel())
+    {
+      if (thr)
+      {
+        tx.append(" ");
+      }
+      if (!gcol.isColourByAttribute())
+      {
+        tx.append("Label");
+      }
+      comp.setIcon(null);
+    }
+    else
+    {
+      Color newColor = gcol.getMaxColour();
+      comp.setBackground(newColor);
+      // System.err.println("Width is " + w / 2);
+      Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
+      comp.setIcon(ficon);
+      // tt+="RGB value: Max (" + newColor.getRed() + ", "
+      // + newColor.getGreen() + ", " + newColor.getBlue()
+      // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
+      // + ", " + minCol.getBlue() + ")");
+    }
+    comp.setHorizontalAlignment(SwingConstants.CENTER);
+    comp.setText(tx.toString());
+  }
+
   // ///////////////////////////////////////////////////////////////////////
   // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
   // ///////////////////////////////////////////////////////////////////////
@@ -1365,11 +1470,9 @@ public class FeatureSettings extends JPanel
 
   class ColorRenderer extends JLabel implements TableCellRenderer
   {
-    javax.swing.border.Border unselectedBorder = null;
+    Border unselectedBorder = null;
 
-    javax.swing.border.Border selectedBorder = null;
-
-    final String baseTT = "Click to edit, right/apple click for menu.";
+    Border selectedBorder = null;
 
     public ColorRenderer()
     {
@@ -1384,7 +1487,6 @@ public class FeatureSettings extends JPanel
     {
       FeatureColourI cellColour = (FeatureColourI) color;
       setOpaque(true);
-      setToolTipText(baseTT);
       setBackground(tbl.getBackground());
       if (!cellColour.isSimpleColour())
       {
@@ -1491,77 +1593,6 @@ public class FeatureSettings extends JPanel
     renderGraduatedColor(comp, gcol, w, h);
   }
 
-  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
-          int w, int h)
-  {
-    boolean thr = false;
-    StringBuilder tt = new StringBuilder();
-    StringBuilder tx = new StringBuilder();
-
-    if (gcol.isColourByAttribute())
-    {
-      tx.append(String.join(":", gcol.getAttributeName()));
-    }
-    else if (!gcol.isColourByLabel())
-    {
-      tx.append(MessageManager.getString("label.score"));
-    }
-    tx.append(" ");
-    if (gcol.isAboveThreshold())
-    {
-      thr = true;
-      tx.append(">");
-      tt.append("Thresholded (Above ").append(gcol.getThreshold())
-              .append(") ");
-    }
-    if (gcol.isBelowThreshold())
-    {
-      thr = true;
-      tx.append("<");
-      tt.append("Thresholded (Below ").append(gcol.getThreshold())
-              .append(") ");
-    }
-    if (gcol.isColourByLabel())
-    {
-      tt.append("Coloured by label text. ").append(tt);
-      if (thr)
-      {
-        tx.append(" ");
-      }
-      if (!gcol.isColourByAttribute())
-      {
-        tx.append("Label");
-      }
-      comp.setIcon(null);
-    }
-    else
-    {
-      Color newColor = gcol.getMaxColour();
-      comp.setBackground(newColor);
-      // System.err.println("Width is " + w / 2);
-      Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
-      comp.setIcon(ficon);
-      // tt+="RGB value: Max (" + newColor.getRed() + ", "
-      // + newColor.getGreen() + ", " + newColor.getBlue()
-      // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
-      // + ", " + minCol.getBlue() + ")");
-    }
-    comp.setHorizontalAlignment(SwingConstants.CENTER);
-    comp.setText(tx.toString());
-    if (tt.length() > 0)
-    {
-      if (comp.getToolTipText() == null)
-      {
-        comp.setToolTipText(tt.toString());
-      }
-      else
-      {
-        comp.setToolTipText(
-                tt.append(" ").append(comp.getToolTipText()).toString());
-      }
-    }
-  }
-
   class ColorEditor extends AbstractCellEditor
           implements TableCellEditor, ActionListener
   {
@@ -1797,7 +1828,6 @@ public class FeatureSettings extends JPanel
       button.setOpaque(true);
       button.setBackground(me.getBackground());
       button.setText(currentFilter.toString());
-      button.setToolTipText(currentFilter.toString());
       button.setIcon(null);
       return button;
     }
index c73e32b..6483b85 100644 (file)
@@ -25,6 +25,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.features.FeatureMatcher;
 import jalview.util.ColorUtils;
 import jalview.util.Format;
+import jalview.util.MessageManager;
 
 import java.awt.Color;
 import java.util.StringTokenizer;
@@ -50,6 +51,12 @@ import java.util.StringTokenizer;
  */
 public class FeatureColour implements FeatureColourI
 {
+  private static final String I18N_LABEL = MessageManager
+          .getString("label.label");
+
+  private static final String I18N_SCORE = MessageManager
+          .getString("label.score");
+
   private static final String ABSOLUTE = "abso";
 
   private static final String ABOVE = "above";
@@ -915,4 +922,50 @@ public class FeatureColour implements FeatureColourI
             || (isBelowThreshold() && scr >= threshold));
   }
 
+  @Override
+  public String getDescription()
+  {
+    if (isSimpleColour())
+    {
+      return "r=" + colour.getRed() + ",g=" + colour.getGreen() + ",b="
+              + colour.getBlue();
+    }
+    StringBuilder tt = new StringBuilder();
+    String by = null;
+
+    if (getAttributeName() != null)
+    {
+      by = FeatureMatcher.toAttributeDisplayName(getAttributeName());
+    }
+    else if (isColourByLabel())
+    {
+      by = I18N_LABEL;
+    }
+    else
+    {
+      by = I18N_SCORE;
+    }
+    tt.append(MessageManager.formatMessage("action.by_title_param", by));
+
+    /*
+     * add threshold if any
+     */
+    if (isAboveThreshold() || isBelowThreshold())
+    {
+      tt.append(" (");
+      if (isColourByLabel())
+      {
+        /*
+         * Jalview features file supports the combination of 
+         * colour by label or attribute text with score threshold
+         */
+        tt.append(I18N_SCORE).append(" ");
+      }
+      tt.append(isAboveThreshold() ? "> " : "< ");
+      tt.append(getThreshold()).append(")");
+    }
+
+    return tt.toString();
+  }
+
 }
index 29c3e56..5219bda 100644 (file)
@@ -13,6 +13,7 @@ import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 import jalview.schemes.FeatureColour;
+import jalview.schemes.FeatureColourTest;
 import jalview.util.matcher.Condition;
 
 import java.awt.Color;
@@ -188,4 +189,42 @@ public class FeatureSettingsTest
     });
     seq.addSequenceFeature(sf);
   }
+
+  /**
+   * @see FeatureColourTest#testGetDescription()
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testGetColorTooltip() throws IOException
+  {
+    assertNull(FeatureSettings.getColorTooltip(null));
+
+    /*
+     * simple colour
+     */
+    FeatureColourI fc = new FeatureColour(Color.black);
+    String simpleTooltip = "Click to edit, right-click for menu";
+    assertEquals(FeatureSettings.getColorTooltip(fc), simpleTooltip);
+
+    /*
+     * graduated colour tooltip includes description of colour
+     */
+    fc.setColourByLabel(true);
+    assertEquals(FeatureSettings.getColorTooltip(fc),
+            "<html>By Label<br>" + simpleTooltip + "</br></html>");
+
+    /*
+     * graduated colour with threshold is html-encoded
+     */
+    fc = new FeatureColour(null, Color.red, Color.blue, null, 2f, 10f);
+    fc.setBelowThreshold(true);
+    fc.setThreshold(4f);
+    assertEquals(FeatureSettings.getColorTooltip(fc),
+            "<html>By Score (&lt; 4.0)<br>" + simpleTooltip
+                    + "</br></html>");
+    fc.setAboveThreshold(true);
+    assertEquals(FeatureSettings.getColorTooltip(fc),
+            "<html>By Score (&gt; 4.0)<br>" + simpleTooltip
+                    + "</br></html>");
+  }
 }
index 8f7ac7c..52ca360 100644 (file)
@@ -700,4 +700,101 @@ public class FeatureColourTest
     sf.setValue("AC", "junk");
     assertFalse(fc.isOutwithThreshold(sf)); // bad value is ignored
   }
+
+  /**
+   * Test description of feature colour suitable for a tooltip
+   */
+  @Test(groups = { "Functional" })
+  public void testGetDescription()
+  {
+    /*
+     * plain colour
+     */
+    FeatureColour fc = new FeatureColour(Color.RED);
+    assertEquals(
+            String.format("r=%d,g=%d,b=%d", Color.RED.getRed(),
+                    Color.red.getGreen(), Color.red.getBlue()),
+            fc.getDescription());
+  
+    /*
+     * colour by label (no threshold)
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    assertEquals("By Label", fc.getDescription());
+  
+    /*
+     * colour by attribute text (no threshold)
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    fc.setAttributeName("CLIN_SIG");
+    assertEquals("By CLIN_SIG", fc.getDescription());
+  
+    /*
+     * colour by label (above score threshold) 
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    fc.setAutoScaled(false);
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    assertEquals("By Label (Score > 12.5)",
+            fc.getDescription());
+  
+    /*
+     * colour by label (below score threshold)
+     */
+    fc.setBelowThreshold(true);
+    assertEquals("By Label (Score < 12.5)",
+            fc.getDescription());
+  
+    /*
+     * colour by attributes text (below score threshold)
+     */
+    fc.setBelowThreshold(true);
+    fc.setAttributeName("CSQ", "Consequence");
+    assertEquals(
+            "By CSQ:Consequence (Score < 12.5)",
+            fc.getDescription());
+  
+    /*
+     * graduated colour by score, no threshold
+     */
+    fc = new FeatureColour(null, Color.GREEN, Color.RED, null, 12f, 25f);
+    assertEquals("By Score", fc.getDescription());
+  
+    /*
+     * graduated colour by score, below threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setBelowThreshold(true);
+    assertEquals("By Score (< 12.5)",
+            fc.getDescription());
+  
+    /*
+     * graduated colour by score, above threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    fc.setAutoScaled(false);
+    assertEquals("By Score (> 12.5)",
+            fc.getDescription());
+
+    /*
+     * graduated colour by attribute, no threshold
+     */
+    fc.setAttributeName("CSQ", "AF");
+    fc.setAboveThreshold(false);
+    fc.setAutoScaled(false);
+    assertEquals("By CSQ:AF", fc.getDescription());
+  
+    /*
+     * graduated colour by attribute, above threshold
+     */
+    fc.setAboveThreshold(true);
+    fc.setAutoScaled(false);
+    assertEquals("By CSQ:AF (> 12.5)",
+            fc.getDescription());
+  }
 }