JAL-2089 patch broken merge to master for Release 2.10.0b1
[jalview.git] / src / jalview / gui / FeatureColourChooser.java
index 993cd2e..5594e1a 100644 (file)
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
- * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * This file is part of Jalview.
  * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.gui;
 
-import java.util.*;
+import jalview.api.FeatureColourI;
+import jalview.datamodel.GraphLine;
+import jalview.schemes.FeatureColour;
+import jalview.util.MessageManager;
 
-import java.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-import javax.swing.event.*;
-
-import jalview.datamodel.*;
-import jalview.schemes.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
 import java.awt.Dimension;
-
-public class FeatureColourChooser extends JPanel
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JColorChooser;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+public class FeatureColourChooser extends JalviewDialog
 {
-  JInternalFrame frame;
-  
+  // FeatureSettings fs;
   FeatureRenderer fr;
 
-  FeatureSettings fs;
+  private FeatureColourI cs;
 
-  GraduatedColor cs;
-  Object oldcs;
+  private FeatureColourI oldcs;
+
+  /**
+   * 
+   * @return the last colour setting selected by user - either oldcs (which may
+   *         be a java.awt.Color) or the new GraduatedColor
+   */
+  public FeatureColourI getLastColour()
+  {
+    if (cs == null)
+    {
+      return oldcs;
+    }
+    return cs;
+  }
 
-  Hashtable oldgroupColours;
-  
   AlignmentPanel ap;
-  
 
   boolean adjusting = false;
 
-  private float min;
+  final private float min;
+
+  final private float max;
+
+  final private float scaleFactor;
 
-  private float max;
   String type = null;
-  public FeatureColourChooser(FeatureSettings fsettings, String type)
+
+  public FeatureColourChooser(FeatureRenderer frender, String type)
+  {
+    this(frender, false, type);
+  }
+
+  public FeatureColourChooser(FeatureRenderer frender, boolean block,
+          String type)
   {
-    this.fs = fsettings;
+    this.fr = frender;
     this.type = type;
-    fr = fsettings.fr;
     ap = fr.ap;
-    frame = new JInternalFrame();
-    frame.setContentPane(this);
-    frame.setLayer(JLayeredPane.PALETTE_LAYER);
-    Desktop.addInternalFrame(frame, "Graduated Feature Colour for "+type, 480, 145);
+    String title = MessageManager.formatMessage(
+            "label.graduated_color_for_params", new String[] { type });
+    initDialogFrame(this, true, block, title, 480, 185);
+    // frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    // Desktop.addInternalFrame(frame, "Graduated Feature Colour for "+type,
+    // 480, 145);
 
     slider.addChangeListener(new ChangeListener()
     {
+      @Override
       public void stateChanged(ChangeEvent evt)
       {
         if (!adjusting)
         {
-          thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
+          thresholdValue.setText((slider.getValue() / scaleFactor) + "");
           valueChanged();
         }
       }
     });
     slider.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mouseReleased(MouseEvent evt)
       {
-        if (fr.ap!=null) { fr.ap.paintAlignment(true); };
+        if (ap != null)
+        {
+          ap.paintAlignment(true);
+        }
+        ;
       }
     });
 
-    float mm[] = ((float[][]) fr.minmax.get(type))[0];
+    float mm[] = fr.getMinMax().get(type)[0];
     min = mm[0];
     max = mm[1];
-    oldcs = fr.featureColours.get(type);
-    if (oldcs instanceof GraduatedColor)
+
+    /*
+     * ensure scale factor allows a scaled range with
+     * 10 integer divisions ('ticks'); if we have got here,
+     * we should expect that max != min
+     */
+    scaleFactor = (max == min) ? 1f : 100f / (max - min);
+
+    oldcs = fr.getFeatureColours().get(type);
+    if (!oldcs.isSimpleColour())
+    {
+      if (oldcs.isAutoScaled())
+      {
+        // update the scale
+        cs = new FeatureColour((FeatureColour) oldcs, min, max);
+      }
+      else
+      {
+        cs = new FeatureColour((FeatureColour) oldcs);
+      }
+    }
+    else
     {
-      cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
-    } else {
       // promote original color to a graduated color
-      Color bl = Color.black;
-      if (oldcs instanceof Color)
+      Color bl = oldcs.getColour();
+      if (bl == null)
       {
-        bl = (Color) oldcs;
+        bl = Color.BLACK;
       }
       // original colour becomes the maximum colour
-      cs = new GraduatedColor(Color.white,bl,mm[0],mm[1]);
+      cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
+      cs.setColourByLabel(false);
     }
-    minColour.setBackground(cs.getMinColor());
-    maxColour.setBackground(cs.getMaxColor());
+    minColour.setBackground(oldminColour = cs.getMinColour());
+    maxColour.setBackground(oldmaxColour = cs.getMaxColour());
     adjusting = true;
-    
+
     try
     {
       jbInit();
     } catch (Exception ex)
     {
     }
+    // update the gui from threshold state
+    thresholdIsMin.setSelected(!cs.isAutoScaled());
+    colourByLabel.setSelected(cs.isColourByLabel());
+    if (cs.hasThreshold())
+    {
+      // initialise threshold slider and selector
+      threshold.setSelectedIndex(cs.isAboveThreshold() ? 1 : 2);
+      slider.setEnabled(true);
+      thresholdValue.setEnabled(true);
+      threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
+
+    }
 
     adjusting = false;
 
     changeColour();
-
-  }
-
-  public FeatureColourChooser()
-  {
-    try
-    {
-      jbInit();
-    } catch (Exception ex)
-    {
-      ex.printStackTrace();
-    }
+    waitForInput();
   }
 
   private void jbInit() throws Exception
   {
-    minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
-    minColour.setBorder(BorderFactory.createEtchedBorder());
+
+    minColour.setFont(JvSwingUtils.getLabelFont());
+    minColour.setBorder(BorderFactory.createLineBorder(Color.black));
     minColour.setPreferredSize(new Dimension(40, 20));
-    minColour.setToolTipText("Minimum Colour");
+    minColour.setToolTipText(MessageManager.getString("label.min_colour"));
     minColour.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         if (minColour.isEnabled())
@@ -142,12 +207,13 @@ public class FeatureColourChooser extends JPanel
         }
       }
     });
-    maxColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
-    maxColour.setBorder(BorderFactory.createEtchedBorder());
+    maxColour.setFont(JvSwingUtils.getLabelFont());
+    maxColour.setBorder(BorderFactory.createLineBorder(Color.black));
     maxColour.setPreferredSize(new Dimension(40, 20));
-    maxColour.setToolTipText("Maximum Colour");
+    maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
     maxColour.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         if (maxColour.isEnabled())
@@ -156,41 +222,35 @@ public class FeatureColourChooser extends JPanel
         }
       }
     });
-    ok.setOpaque(false);
-    ok.setText("OK");
-    ok.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        ok_actionPerformed(e);
-      }
-    });
-    cancel.setOpaque(false);
-    cancel.setText("Cancel");
-    cancel.addActionListener(new ActionListener()
-    {
-      public void actionPerformed(ActionEvent e)
-      {
-        cancel_actionPerformed(e);
-      }
-    });
+    maxColour.setBorder(new LineBorder(Color.black));
+    minText.setText(MessageManager.getString("label.min"));
+    minText.setFont(JvSwingUtils.getLabelFont());
+    maxText.setText(MessageManager.getString("label.max"));
+    maxText.setFont(JvSwingUtils.getLabelFont());
     this.setLayout(borderLayout1);
     jPanel2.setLayout(flowLayout1);
     jPanel1.setBackground(Color.white);
     jPanel2.setBackground(Color.white);
     threshold.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         threshold_actionPerformed(e);
       }
     });
-    threshold.addItem("No Threshold");
-    threshold.addItem("Above Threshold");
-    threshold.addItem("Below Threshold");
+    threshold.setToolTipText(MessageManager
+            .getString("label.threshold_feature_display_by_score"));
+    threshold.addItem(MessageManager
+            .getString("label.threshold_feature_no_threshold")); // index 0
+    threshold.addItem(MessageManager
+            .getString("label.threshold_feature_above_threshold")); // index 1
+    threshold.addItem(MessageManager
+            .getString("label.threshold_feature_below_threshold")); // index 2
     jPanel3.setLayout(flowLayout2);
     thresholdValue.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         thresholdValue_actionPerformed(e);
@@ -202,33 +262,47 @@ public class FeatureColourChooser extends JPanel
     slider.setEnabled(false);
     slider.setOpaque(false);
     slider.setPreferredSize(new Dimension(100, 32));
+    slider.setToolTipText(MessageManager
+            .getString("label.adjust_threshold"));
     thresholdValue.setEnabled(false);
     thresholdValue.setColumns(7);
     jPanel3.setBackground(Color.white);
-    currentColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
-    currentColours.setOpaque(false);
-    currentColours.setText("Use Original Colours");
-    currentColours.addActionListener(new ActionListener()
+    thresholdIsMin.setBackground(Color.white);
+    thresholdIsMin.setText(MessageManager
+            .getString("label.threshold_minmax"));
+    thresholdIsMin.setToolTipText(MessageManager
+            .getString("label.toggle_absolute_relative_display_threshold"));
+    thresholdIsMin.addActionListener(new ActionListener()
     {
-      public void actionPerformed(ActionEvent e)
+      @Override
+      public void actionPerformed(ActionEvent actionEvent)
       {
-        currentColours_actionPerformed(e);
+        thresholdIsMin_actionPerformed(actionEvent);
       }
     });
-    thresholdIsMin.setBackground(Color.white);
-    thresholdIsMin.setText("Threshold is Min/Max");
-    thresholdIsMin.addActionListener(new ActionListener()
+    colourByLabel.setBackground(Color.white);
+    colourByLabel
+            .setText(MessageManager.getString("label.colour_by_label"));
+    colourByLabel
+            .setToolTipText(MessageManager
+                    .getString("label.display_features_same_type_different_label_using_different_colour"));
+    colourByLabel.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent actionEvent)
       {
-        thresholdIsMin_actionPerformed(actionEvent);
+        colourByLabel_actionPerformed(actionEvent);
       }
     });
+    colourPanel.setBackground(Color.white);
     jPanel1.add(ok);
     jPanel1.add(cancel);
-    // jPanel2.add(currentColours);
-    jPanel2.add(minColour);
-    jPanel2.add(maxColour);
+    jPanel2.add(colourByLabel, java.awt.BorderLayout.WEST);
+    jPanel2.add(colourPanel, java.awt.BorderLayout.EAST);
+    colourPanel.add(minText);
+    colourPanel.add(minColour);
+    colourPanel.add(maxText);
+    colourPanel.add(maxColour);
     this.add(jPanel3, java.awt.BorderLayout.CENTER);
     jPanel3.add(threshold);
     jPanel3.add(slider);
@@ -238,14 +312,15 @@ public class FeatureColourChooser extends JPanel
     this.add(jPanel2, java.awt.BorderLayout.NORTH);
   }
 
+  JLabel minText = new JLabel();
+
+  JLabel maxText = new JLabel();
 
   JPanel minColour = new JPanel();
 
   JPanel maxColour = new JPanel();
 
-  JButton ok = new JButton();
-
-  JButton cancel = new JButton();
+  JPanel colourPanel = new JPanel();
 
   JPanel jPanel1 = new JPanel();
 
@@ -264,20 +339,29 @@ public class FeatureColourChooser extends JPanel
   JSlider slider = new JSlider();
 
   JTextField thresholdValue = new JTextField(20);
-  // TODO refactor to tolower flag
-  JCheckBox currentColours = new JCheckBox();
+
+  // TODO implement GUI for tolower flag
+  // JCheckBox toLower = new JCheckBox();
 
   JCheckBox thresholdIsMin = new JCheckBox();
 
+  JCheckBox colourByLabel = new JCheckBox();
+
   private GraphLine threshline;
 
+  private Color oldmaxColour;
+
+  private Color oldminColour;
+
   public void minColour_actionPerformed()
   {
     Color col = JColorChooser.showDialog(this,
-            "Select Colour for Minimum Value", minColour.getBackground());
+            MessageManager.getString("label.select_colour_minimum_value"),
+            minColour.getBackground());
     if (col != null)
     {
       minColour.setBackground(col);
+      minColour.setForeground(col);
     }
     minColour.repaint();
     changeColour();
@@ -286,10 +370,12 @@ public class FeatureColourChooser extends JPanel
   public void maxColour_actionPerformed()
   {
     Color col = JColorChooser.showDialog(this,
-            "Select Colour for Maximum Value", maxColour.getBackground());
+            MessageManager.getString("label.select_colour_maximum_value"),
+            maxColour.getBackground());
     if (col != null)
     {
       maxColour.setBackground(col);
+      maxColour.setForeground(col);
     }
     maxColour.repaint();
     changeColour();
@@ -303,95 +389,133 @@ public class FeatureColourChooser extends JPanel
       return;
     }
 
-
-    int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD;
-    if (threshold.getSelectedItem().equals("Above Threshold"))
+    boolean aboveThreshold = false;
+    boolean belowThreshold = false;
+    if (threshold.getSelectedIndex() == 1)
     {
-      aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
+      aboveThreshold = true;
     }
-    else if (threshold.getSelectedItem().equals("Below Threshold"))
+    else if (threshold.getSelectedIndex() == 2)
     {
-      aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
-    } 
+      belowThreshold = true;
+    }
+    boolean hasThreshold = aboveThreshold || belowThreshold;
 
     slider.setEnabled(true);
     thresholdValue.setEnabled(true);
-    GraduatedColor acg = new GraduatedColor(minColour.getBackground(), maxColour.getBackground(), min, max);
 
-    if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
+    FeatureColourI acg;
+    if (cs.isColourByLabel())
+    {
+      acg = new FeatureColour(oldminColour, oldmaxColour, min, max);
+    }
+    else
+    {
+      acg = new FeatureColour(oldminColour = minColour.getBackground(),
+              oldmaxColour = maxColour.getBackground(), min, max);
+
+    }
+
+    if (!hasThreshold)
     {
       slider.setEnabled(false);
       thresholdValue.setEnabled(false);
       thresholdValue.setText("");
+      thresholdIsMin.setEnabled(false);
     }
-    else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
-            && threshline == null)
+    else if (threshline == null)
     {
       // todo visual indication of feature threshold
-      threshline = new jalview.datamodel.GraphLine(
-                      (max - min) / 2f,
-                      "Threshold", Color.black);
+      threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
     }
 
-    if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    if (hasThreshold)
     {
       adjusting = true;
-      acg.setThresh(threshline.value);
+      acg.setThreshold(threshline.value);
 
-      float range = max * 1000f
-              - min * 1000f;
+      float range = (max - min) * scaleFactor;
 
-      slider.setMinimum((int) (min * 1000));
-      slider.setMaximum((int) (max * 1000));
-      slider.setValue((int) (threshline.value * 1000));
+      slider.setMinimum((int) (min * scaleFactor));
+      slider.setMaximum((int) (max * scaleFactor));
+      slider.setValue((int) (threshline.value * scaleFactor));
       thresholdValue.setText(threshline.value + "");
       slider.setMajorTickSpacing((int) (range / 10f));
       slider.setEnabled(true);
       thresholdValue.setEnabled(true);
+      thresholdIsMin.setEnabled(!colourByLabel.isSelected());
       adjusting = false;
     }
 
-    acg.setThreshType(aboveThreshold);
-    if (thresholdIsMin.isSelected() && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    acg.setAboveThreshold(aboveThreshold);
+    acg.setBelowThreshold(belowThreshold);
+    if (thresholdIsMin.isSelected() && hasThreshold)
     {
-      if (aboveThreshold==AnnotationColourGradient.ABOVE_THRESHOLD)
-      { 
-        acg = new GraduatedColor(acg, threshline.value, max);
-      } else { 
-        acg = new GraduatedColor(acg, min,threshline.value);
+      acg.setAutoScaled(false);
+      if (aboveThreshold)
+      {
+        acg = new FeatureColour((FeatureColour) acg, threshline.value, max);
+      }
+      else
+      {
+        acg = new FeatureColour((FeatureColour) acg, min, threshline.value);
       }
     }
-    
-    fr.featureColours.put(type,acg);
+    else
+    {
+      acg.setAutoScaled(true);
+    }
+    acg.setColourByLabel(colourByLabel.isSelected());
+    if (acg.isColourByLabel())
+    {
+      maxColour.setEnabled(false);
+      minColour.setEnabled(false);
+      maxColour.setBackground(this.getBackground());
+      maxColour.setForeground(this.getBackground());
+      minColour.setBackground(this.getBackground());
+      minColour.setForeground(this.getBackground());
+
+    }
+    else
+    {
+      maxColour.setEnabled(true);
+      minColour.setEnabled(true);
+      maxColour.setBackground(oldmaxColour);
+      minColour.setBackground(oldminColour);
+      maxColour.setForeground(oldmaxColour);
+      minColour.setForeground(oldminColour);
+    }
+    fr.setColour(type, acg);
     cs = acg;
     ap.paintAlignment(false);
   }
 
-  public void ok_actionPerformed(ActionEvent e)
+  @Override
+  protected void raiseClosed()
   {
-    changeColour();
-    try
-    {
-      frame.setClosed(true);
-    } catch (Exception ex)
+    if (this.colourEditor != null)
     {
+      colourEditor.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
     }
   }
 
-  public void cancel_actionPerformed(ActionEvent e)
+  @Override
+  public void okPressed()
+  {
+    changeColour();
+  }
+
+  @Override
+  public void cancelPressed()
   {
     reset();
-    try
-    {
-      frame.setClosed(true);
-    } catch (Exception ex)
-    {
-    }
   }
 
   void reset()
   {
-    fr.featureColours.put(type, oldcs);
+    fr.setColour(type, oldcs);
+    ap.paintAlignment(false);
+    cs = null;
   }
 
   public void thresholdCheck_actionPerformed(ActionEvent e)
@@ -414,7 +538,7 @@ public class FeatureColourChooser extends JPanel
     try
     {
       float f = Float.parseFloat(thresholdValue.getText());
-      slider.setValue((int) (f * 1000));
+      slider.setValue((int) (f * scaleFactor));
       threshline.value = f;
     } catch (NumberFormatException ex)
     {
@@ -423,28 +547,32 @@ public class FeatureColourChooser extends JPanel
 
   public void valueChanged()
   {
-    threshline.value = (float) slider.getValue() / 1000f;
-    cs.setThresh(threshline.value);
+    threshline.value = slider.getValue() / scaleFactor;
+    cs.setThreshold(threshline.value);
     changeColour();
     ap.paintAlignment(false);
   }
 
-  public void currentColours_actionPerformed(ActionEvent e)
+  public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
   {
-    if (currentColours.isSelected())
-    {
-      reset();
-    }
-
-    maxColour.setEnabled(!currentColours.isSelected());
-    minColour.setEnabled(!currentColours.isSelected());
-
     changeColour();
   }
 
-  public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
+  public void colourByLabel_actionPerformed(ActionEvent actionEvent)
   {
     changeColour();
   }
 
+  ActionListener colourEditor = null;
+
+  public void addActionListener(ActionListener graduatedColorEditor)
+  {
+    if (colourEditor != null)
+    {
+      System.err
+              .println("IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
+    }
+    colourEditor = graduatedColorEditor;
+  }
+
 }