From: gmungoc Date: Tue, 5 Mar 2019 09:01:48 +0000 (+0000) Subject: Merge remote-tracking branch 'origin/bug/JAL-3049colourCellTooltip' into X-Git-Tag: Release_2_11_0~17^2~74 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=ee7d621eea4811c90ce8bc470cc1e217cd2d806c Merge remote-tracking branch 'origin/bug/JAL-3049colourCellTooltip' into merge/JAL-3049 Conflicts: src/jalview/api/FeatureColourI.java src/jalview/schemes/FeatureColour.java test/jalview/schemes/FeatureColourTest.java --- ee7d621eea4811c90ce8bc470cc1e217cd2d806c diff --cc src/jalview/api/FeatureColourI.java index 999104c,0e45675..7bfd8a8 --- a/src/jalview/api/FeatureColourI.java +++ b/src/jalview/api/FeatureColourI.java @@@ -194,14 -194,10 +194,22 @@@ public interface FeatureColour void setAttributeName(String... name); /** + * Answers true if colour has a threshold set, and the feature score (or other + * attribute selected for colouring) is outwith the threshold. + *

+ * Answers false if not a graduated colour, or no threshold is set, or value + * is not outwith the threshold, or value is null or non-numeric. + * + * @param sf + * @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(); } diff --cc src/jalview/gui/FeatureSettings.java index 534a088,7fb3af9..40e49fb --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@@ -222,10 -233,23 +234,25 @@@ public class FeatureSettings extends JP } 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; + } }; - table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12)); + JTableHeader tableHeader = table.getTableHeader(); + tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12)); + tableHeader.setReorderingAllowed(false); table.setFont(new Font("Verdana", Font.PLAIN, 12)); // table.setDefaultRenderer(Color.class, new ColorRenderer()); diff --cc src/jalview/schemes/FeatureColour.java index c73e32b,e683c87..6483b85 --- a/src/jalview/schemes/FeatureColour.java +++ b/src/jalview/schemes/FeatureColour.java @@@ -888,31 -898,49 +895,77 @@@ public class FeatureColour implements F } @Override + public boolean isOutwithThreshold(SequenceFeature feature) + { + if (!isGraduatedColour()) + { + return false; + } + float scr = feature.getScore(); + if (attributeName != null) + { + try + { + String attVal = feature.getValueAsString(attributeName); + scr = Float.valueOf(attVal); + } catch (Throwable e) + { + scr = Float.NaN; + } + } + if (Float.isNaN(scr)) + { + return false; + } + + return ((isAboveThreshold() && scr <= threshold) + || (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(); + } + } diff --cc test/jalview/gui/FeatureSettingsTest.java index 29c3e56,db37733..5219bda --- a/test/jalview/gui/FeatureSettingsTest.java +++ b/test/jalview/gui/FeatureSettingsTest.java @@@ -188,4 -189,42 +189,42 @@@ public class FeatureSettingsTes }); 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), + "By Label
" + simpleTooltip + "
"); + + /* + * graduated colour with threshold is html-encoded + */ - fc = new FeatureColour(Color.red, Color.blue, 2f, 10f); ++ fc = new FeatureColour(null, Color.red, Color.blue, null, 2f, 10f); + fc.setBelowThreshold(true); + fc.setThreshold(4f); + assertEquals(FeatureSettings.getColorTooltip(fc), + "By Score (< 4.0)
" + simpleTooltip + + "
"); + fc.setAboveThreshold(true); + assertEquals(FeatureSettings.getColorTooltip(fc), + "By Score (> 4.0)
" + simpleTooltip + + "
"); + } } diff --cc test/jalview/schemes/FeatureColourTest.java index 8f7ac7c,754e077..52ca360 --- a/test/jalview/schemes/FeatureColourTest.java +++ b/test/jalview/schemes/FeatureColourTest.java @@@ -660,44 -664,100 +660,141 @@@ public class FeatureColourTes assertEquals(expected, fc.getColor(sf)); } + @Test(groups = { "Functional" }) + public void testIsOutwithThreshold() + { + FeatureColourI fc = new FeatureColour(Color.red); + SequenceFeature sf = new SequenceFeature("METAL", "desc", 10, 12, 1.2f, "grp"); + assertFalse(fc.isOutwithThreshold(null)); + assertFalse(fc.isOutwithThreshold(sf)); + + fc = new FeatureColour(null, Color.white, Color.black, Color.green, 0f, + 10f); + assertFalse(fc.isOutwithThreshold(sf)); // no threshold + + fc.setAboveThreshold(true); + fc.setThreshold(1f); + assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is above 1 + + fc.setThreshold(2f); + assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not above 2 + + fc.setBelowThreshold(true); + assertFalse(fc.isOutwithThreshold(sf)); // feature score 1.2 is below 2 + + fc.setThreshold(1f); + assertTrue(fc.isOutwithThreshold(sf)); // feature score 1.2 is not below 1 + + /* + * with attribute value threshold + */ + fc.setAttributeName("AC"); + assertFalse(fc.isOutwithThreshold(sf)); // missing attribute AC is ignored + + sf.setValue("AC", "-1"); + assertFalse(fc.isOutwithThreshold(sf)); // value -1 is below 1 + + sf.setValue("AC", "1"); + assertTrue(fc.isOutwithThreshold(sf)); // value 1 is not below 1 + + 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(Color.GREEN, Color.RED, 12f, 25f); ++ 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()); + } }