JAL-2544 unit tests for sort by feature score
[jalview.git] / src / jalview / gui / FeatureSettings.java
index 7d9e937..34f0b4a 100644 (file)
@@ -27,6 +27,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.Help.HelpId;
 import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
 import jalview.schemabinding.version2.JalviewUserColours;
 import jalview.schemes.FeatureColour;
 import jalview.util.Format;
@@ -39,6 +40,7 @@ import jalview.ws.dbsources.das.api.jalviewSourceI;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
+import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.GridLayout;
@@ -59,6 +61,7 @@ import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
@@ -79,7 +82,6 @@ import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
 import javax.swing.JLayeredPane;
 import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
@@ -126,6 +128,15 @@ public class FeatureSettings extends JPanel implements
 
   JPanel transPanel = new JPanel(new GridLayout(1, 2));
 
+  private static final int MIN_WIDTH = 400;
+
+  private static final int MIN_HEIGHT = 400;
+
+  /**
+   * Constructor
+   * 
+   * @param af
+   */
   public FeatureSettings(AlignFrame af)
   {
     this.af = af;
@@ -174,7 +185,7 @@ public class FeatureSettings extends JPanel implements
       public void mousePressed(MouseEvent evt)
       {
         selectedRow = table.rowAtPoint(evt.getPoint());
-        if (SwingUtilities.isRightMouseButton(evt))
+        if (evt.isPopupTrigger())
         {
           popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
                   table.getValueAt(selectedRow, 1), fr.getMinMax(),
@@ -182,14 +193,16 @@ public class FeatureSettings extends JPanel implements
         }
         else if (evt.getClickCount() == 2)
         {
+          boolean invertSelection = evt.isAltDown();
+          boolean toggleSelection = Platform.isControlDown(evt);
+          boolean extendSelection = evt.isShiftDown();
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
-                  evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
-                  evt.isMetaDown(),
+                  invertSelection, extendSelection, toggleSelection,
                   (String) table.getValueAt(selectedRow, 0));
         }
       }
 
-      // isPopupTrigger fires on mouseReleased on Mac
+      // isPopupTrigger fires on mouseReleased on Windows
       @Override
       public void mouseReleased(MouseEvent evt)
       {
@@ -276,6 +289,7 @@ public class FeatureSettings extends JPanel implements
               MessageManager.getString("label.sequence_feature_settings"),
               400, 450);
     }
+    frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
 
     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
     {
@@ -523,27 +537,15 @@ public class FeatureSettings extends JPanel implements
   {
     boolean visible = fr.checkGroupVisibility(group, true);
 
-    if (groupPanel == null)
-    {
-      groupPanel = new JPanel();
-    }
-
-    boolean alreadyAdded = false;
     for (int g = 0; g < groupPanel.getComponentCount(); g++)
     {
       if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
       {
-        alreadyAdded = true;
         ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
-        break;
+        return visible;
       }
     }
 
-    if (alreadyAdded)
-    {
-
-      return visible;
-    }
     final String grp = group;
     final JCheckBox check = new JCheckBox(group, visible);
     check.setFont(new Font("Serif", Font.BOLD, 12));
@@ -582,6 +584,7 @@ public class FeatureSettings extends JPanel implements
     SequenceFeature[] tmpfeatures;
     String group = null, type;
     Vector<String> visibleChecks = new Vector<String>();
+    Set<String> foundGroups = new HashSet<String>();
 
     // Find out which features should be visible depending on which groups
     // are selected / deselected
@@ -600,6 +603,7 @@ public class FeatureSettings extends JPanel implements
       while (index < tmpfeatures.length)
       {
         group = tmpfeatures[index].featureGroup;
+        foundGroups.add(group);
 
         if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
         {
@@ -700,24 +704,105 @@ public class FeatureSettings extends JPanel implements
         System.arraycopy(data[i], 0, originalData[i], 0, 3);
       }
     }
+    else
+    {
+      updateOriginalData(data);
+    }
 
     table.setModel(new FeatureTableModel(data));
     table.getColumnModel().getColumn(0).setPreferredWidth(200);
 
-    if (groupPanel != null)
-    {
-      groupPanel.setLayout(new GridLayout(
-              fr.getFeatureGroupsSize() / 4 + 1, 4));
-
-      groupPanel.validate();
-      bigPanel.add(groupPanel, BorderLayout.NORTH);
-    }
+    groupPanel.setLayout(new GridLayout(fr.getFeatureGroupsSize() / 4 + 1,
+            4));
+    pruneGroups(foundGroups);
+    groupPanel.validate();
 
     updateFeatureRenderer(data, groupChanged != null);
     resettingTable = false;
   }
 
   /**
+   * Updates 'originalData' (used for restore on Cancel) if we detect that
+   * changes have been made outwith this dialog
+   * <ul>
+   * <li>a new feature type added (and made visible)</li>
+   * <li>a feature colour changed (in the Amend Features dialog)</li>
+   * </ul>
+   * 
+   * @param foundData
+   */
+  protected void updateOriginalData(Object[][] foundData)
+  {
+    // todo LinkedHashMap instead of Object[][] would be nice
+
+    Object[][] currentData = ((FeatureTableModel) table.getModel())
+            .getData();
+    for (Object[] row : foundData)
+    {
+      String type = (String) row[0];
+      boolean found = false;
+      for (Object[] current : currentData)
+      {
+        if (type.equals(current[0]))
+        {
+          found = true;
+          /*
+           * currently dependent on object equality here;
+           * really need an equals method on FeatureColour
+           */
+          if (!row[1].equals(current[1]))
+          {
+            /*
+             * feature colour has changed externally - update originalData
+             */
+            for (Object[] original : originalData)
+            {
+              if (type.equals(original[0]))
+              {
+                original[1] = row[1];
+                break;
+              }
+            }
+          }
+          break;
+        }
+      }
+      if (!found)
+      {
+        /*
+         * new feature detected - add to original data (on top)
+         */
+        Object[][] newData = new Object[originalData.length + 1][3];
+        for (int i = 0; i < originalData.length; i++)
+        {
+          System.arraycopy(originalData[i], 0, newData[i + 1], 0, 3);
+        }
+        newData[0] = row;
+        originalData = newData;
+      }
+    }
+  }
+
+  /**
+   * Remove from the groups panel any checkboxes for groups that are not in the
+   * foundGroups set. This enables removing a group from the display when the
+   * last feature in that group is deleted.
+   * 
+   * @param foundGroups
+   */
+  protected void pruneGroups(Set<String> foundGroups)
+  {
+    for (int g = 0; g < groupPanel.getComponentCount(); g++)
+    {
+      JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
+      if (!foundGroups.contains(checkbox.getText()))
+      {
+        groupPanel.remove(checkbox);
+      }
+    }
+  }
+
+  /**
    * reorder data based on the featureRenderers global priority list.
    * 
    * @param data
@@ -746,12 +831,9 @@ public class FeatureSettings extends JPanel implements
 
   void load()
   {
-    JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
-            new String[] { "fc" },
-            new String[] { "Sequence Feature Colours" },
+    JalviewFileChooser chooser = new JalviewFileChooser("fc",
             "Sequence Feature Colours");
-    chooser.setFileView(new jalview.io.JalviewFileView());
+    chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager
             .getString("label.load_feature_colours"));
     chooser.setToolTipText(MessageManager.getString("action.load"));
@@ -841,12 +923,9 @@ public class FeatureSettings extends JPanel implements
 
   void save()
   {
-    JalviewFileChooser chooser = new JalviewFileChooser(
-            Cache.getProperty("LAST_DIRECTORY"),
-            new String[] { "fc" },
-            new String[] { "Sequence Feature Colours" },
+    JalviewFileChooser chooser = new JalviewFileChooser("fc",
             "Sequence Feature Colours");
-    chooser.setFileView(new jalview.io.JalviewFileView());
+    chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager
             .getString("label.save_feature_colours"));
     chooser.setToolTipText(MessageManager.getString("action.save"));
@@ -1063,6 +1142,10 @@ public class FeatureSettings extends JPanel implements
     settingsPane.setLayout(borderLayout2);
     dasSettingsPane.setLayout(borderLayout3);
     bigPanel.setLayout(borderLayout4);
+
+    groupPanel = new JPanel();
+    bigPanel.add(groupPanel, BorderLayout.NORTH);
+
     invert.setFont(JvSwingUtils.getLabelFont());
     invert.setText(MessageManager.getString("label.invert_selection"));
     invert.addActionListener(new ActionListener()
@@ -1401,15 +1484,15 @@ public class FeatureSettings extends JPanel implements
   public void noDasSourceActive()
   {
     complete();
-    JOptionPane
+    JvOptionPane
             .showInternalConfirmDialog(
                     Desktop.desktop,
                     MessageManager
                             .getString("label.no_das_sources_selected_warn"),
                     MessageManager
                             .getString("label.no_das_sources_selected_title"),
-                    JOptionPane.DEFAULT_OPTION,
-                    JOptionPane.INFORMATION_MESSAGE);
+                    JvOptionPane.DEFAULT_OPTION,
+                    JvOptionPane.INFORMATION_MESSAGE);
   }
 
   // ///////////////////////////////////////////////////////////////////////