Merge branch 'bug/JAL-3049colourCellTooltip' into Jalview-BH/JAL-3026
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 6 Jul 2018 09:41:57 +0000 (10:41 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 6 Jul 2018 09:41:57 +0000 (10:41 +0100)
1  2 
src/jalview/gui/FeatureSettings.java

@@@ -24,11 -24,11 +24,12 @@@ 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;
  import jalview.gui.Help.HelpId;
 +import jalview.gui.JalviewColourChooser.ColourChooserListener;
  import jalview.io.JalviewFileChooser;
  import jalview.io.JalviewFileView;
  import jalview.schemabinding.version2.Filter;
@@@ -93,6 -93,7 +94,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;
@@@ -123,6 -124,8 +125,8 @@@ public class FeatureSettings extends JP
  
    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;
     */
    Object[][] originalData;
  
 -  private float originalTransparency;
 +  float originalTransparency;
  
 -  private Map<String, FeatureMatcherSetI> originalFilters;
 +  Map<String, FeatureMatcherSetI> originalFilters;
  
    final JInternalFrame frame;
  
    /*
     * true when Feature Settings are updating from feature renderer
     */
 -  private boolean handlingUpdate = false;
 +  boolean handlingUpdate = false;
  
    /*
     * holds {featureCount, totalExtent} for each feature type
  
      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()
          }
          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));
      table.setFont(new Font("Verdana", Font.PLAIN, 12));
  
      table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
      table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
 -
 +    
      TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
              new ColorRenderer(), new ColorEditor(this));
      table.addColumn(colourColumn);
       * variable colour options include colour by label, by score,
       * by selected attribute text, or attribute value
       */
 -    final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
 +    final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
              MessageManager.getString("label.variable_colour"));
 -    mxcol.setSelected(!featureColour.isSimpleColour());
 -    men.add(mxcol);
 -    mxcol.addActionListener(new ActionListener()
 +    variableColourCB.setSelected(!featureColour.isSimpleColour());
 +    men.add(variableColourCB);
 +    
 +    /*
 +     * checkbox action listener doubles up as listener to OK
 +     * from the variable colour / filters dialog
 +     */
 +    variableColourCB.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        if (e.getSource() == mxcol)
 +        if (e.getSource() == variableColourCB)
          {
            if (featureColour.isSimpleColour())
            {
 +            /*
 +             * toggle simple colour to variable colour - show dialog
 +             */
              FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
              fc.addActionListener(this);
            }
            else
            {
 -            // bring up simple color chooser
 -            colorChooser = new JColorChooser();
 -            String title = MessageManager
 -                    .getString("label.select_colour");
 -            JDialog dialog = JColorChooser.createDialog(me,
 -                    title, true, // modal
 -                    colorChooser, this, // OK button handler
 -                    null); // no CANCEL button handler
 -            colorChooser.setColor(featureColour.getMaxColour());
 -            dialog.setVisible(true);
 +            /*
 +             * toggle variable to simple colour - show colour chooser
 +             */
 +            String title = MessageManager.getString("label.select_colour");
 +            ColourChooserListener listener = new ColourChooserListener()
 +            {
 +              @Override
 +              public void colourSelected(Color c)
 +              {
 +                table.setValueAt(new FeatureColour(c), rowSelected,
 +                        COLOUR_COLUMN);
 +                table.validate();
 +                me.updateFeatureRenderer(
 +                        ((FeatureTableModel) table.getModel()).getData(),
 +                        false);
 +              }
 +            };
 +            JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
            }
          }
 -        else
 -        {
 +        else    {
            if (e.getSource() instanceof FeatureTypeSettings)
            {
              /*
               * colour will have already been set in the FeatureRenderer
               */
              FeatureColourI fci = fr.getFeatureColours().get(type);
 -            table.setValueAt(fci, rowSelected, 1);
 +            table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
              table.validate();
            }
 -          else
 -          {
 -            // probably the color chooser!
 -            table.setValueAt(new FeatureColour(colorChooser.getColor()),
 -                    rowSelected, 1);
 -            table.validate();
 -            me.updateFeatureRenderer(
 -                    ((FeatureTableModel) table.getModel()).getData(),
 -                    false);
 -          }
          }
        }
  
     */
    void load()
    {
 +    // TODO: JAL-3048 relies on Castor XML parsing: not needed for JS-jalview core
 +    // functionalty
 +
      JalviewFileChooser chooser = new JalviewFileChooser("fc",
              SEQUENCE_FEATURE_COLOURS);
      chooser.setFileView(new JalviewFileView());
     */
    void save()
    {
 +    // TODO: JAL-3048 not needed for Jalview-JS - save colours
      JalviewFileChooser chooser = new JalviewFileChooser("fc",
              SEQUENCE_FEATURE_COLOURS);
      chooser.setFileView(new JalviewFileView());
     * @param data
     * @param visibleNew
     */
 -  private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
 +  void updateFeatureRenderer(Object[][] data, boolean visibleNew)
    {
      FeatureSettingsBean[] rowData = getTableAsBeans(data);
  
      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
    // ///////////////////////////////////////////////////////////////////////
  
    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()
      {
      {
        FeatureColourI cellColour = (FeatureColourI) color;
        setOpaque(true);
-       setToolTipText(baseTT);
        setBackground(tbl.getBackground());
        if (!cellColour.isSimpleColour())
        {
      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
    {
  
      JButton button;
  
 -    JColorChooser colorChooser;
 -
 -    JDialog dialog;
 -
      protected static final String EDIT = "edit";
  
      int rowSelected = 0;
  
 -    public ColorEditor(FeatureSettings me)
 +    public ColorEditor(FeatureSettings fs)
      {
 -      this.me = me;
 +      this.me = fs;
        // Set up the editor (from the table's point of view),
        // which is a button.
        // This button brings up the color chooser dialog,
        button.setActionCommand(EDIT);
        button.addActionListener(this);
        button.setBorderPainted(false);
      }
  
      /**
 -     * Handles events from the editor button and from the dialog's OK button.
 +     * Handles events from the editor button, and from the colour/filters
 +     * dialog's OK button
       */
      @Override
      public void actionPerformed(ActionEvent e)
      {
 -      // todo test e.getSource() instead here
 -      if (EDIT.equals(e.getActionCommand()))
 +      if (button == e.getSource())
        {
 -        // The user has clicked the cell, so
 -        // bring up the dialog.
          if (currentColor.isSimpleColour())
          {
 -          // bring up simple color chooser
 -          button.setBackground(currentColor.getColour());
 -          colorChooser.setColor(currentColor.getColour());
 -          dialog.setVisible(true);
 +          /*
 +           * simple colour chooser
 +           */
 +          String ttl = MessageManager.getString("label.select_colour");
 +          ColourChooserListener listener = new ColourChooserListener() {
 +            @Override
 +            public void colourSelected(Color c)
 +            {
 +              currentColor = new FeatureColour(c);
 +              me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
 +            }
 +          };
 +          JalviewColourChooser.showColourChooser(button,  ttl,  currentColor.getColour(), listener);
          }
          else
          {
 -          // bring up graduated chooser.
 +          /*
 +           * variable colour and filters dialog
 +           */
            chooser = new FeatureTypeSettings(me.fr, type);
 -          chooser.setRequestFocusEnabled(true);
 -          chooser.requestFocus();
 +          /**
 +           * @j2sNative
 +           */
 +          {
 +            chooser.setRequestFocusEnabled(true);
 +            chooser.requestFocus();
 +          }
            chooser.addActionListener(this);
 -          chooser.showTab(true);
 +          // Make the renderer reappear.
 +          fireEditingStopped();
          }
        }
        else
        {
 -        if (currentColor.isSimpleColour())
 -        {
 -          /*
 -           * read off colour picked in colour chooser after OK pressed
 -           */
 -          currentColor = new FeatureColour(colorChooser.getColor());
 -          me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
 -        }
 -        else
 +        /*
 +         * after OK in variable colour dialog, any changes to colour 
 +         * (or filters!) are already set in FeatureRenderer, so just
 +         * update table data without triggering updateFeatureRenderer
 +         */
 +        currentColor = fr.getFeatureColours().get(type);
 +        FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
 +        if (currentFilter == null)
          {
 -          /*
 -           * after OK in variable colour dialog, any changes to colour 
 -           * (or filters!) are already set in FeatureRenderer, so just
 -           * update table data without triggering updateFeatureRenderer
 -           */
 -          currentColor = fr.getFeatureColours().get(type);
 -          FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
 -          if (currentFilter == null)
 -          {
 -            currentFilter = new FeatureMatcherSet();
 -          }
 -          Object[] data = ((FeatureTableModel) table.getModel())
 -                  .getData()[rowSelected];
 -          data[COLOUR_COLUMN] = currentColor;
 -          data[FILTER_COLUMN] = currentFilter;
 +          currentFilter = new FeatureMatcherSet();
          }
 +        Object[] data = ((FeatureTableModel) table.getModel())
 +                .getData()[rowSelected];
 +        data[COLOUR_COLUMN] = currentColor;
 +        data[FILTER_COLUMN] = currentFilter;
 +
          fireEditingStopped();
          me.table.validate();
        }
                    chooser.getWidth(), chooser.getHeight());
            chooser.validate();
          }
 -        chooser.showTab(false);
          fireEditingStopped();
        }
        else if (e.getSource() instanceof Component)
        button.setOpaque(true);
        button.setBackground(me.getBackground());
        button.setText(currentFilter.toString());
-       button.setToolTipText(currentFilter.toString());
        button.setIcon(null);
        return button;
      }